| rev |
line source |
| dagss@1154 | 1 cimport python_buffer as pybuf
|
| dagss@1235 | 2 cimport stdlib
|
| dagss@1154 | 3
|
| dagss@778 | 4 cdef extern from "Python.h":
|
| dagss@778 | 5 ctypedef int Py_intptr_t
|
| dagss@778 | 6
|
| dagss@778 | 7 cdef extern from "numpy/arrayobject.h":
|
| dagss@980 | 8 ctypedef Py_intptr_t npy_intp
|
| robertwb@1023 | 9
|
| dagss@1026 | 10 cdef enum:
|
| dagss@1026 | 11 NPY_BOOL,
|
| dagss@1026 | 12 NPY_BYTE, NPY_UBYTE,
|
| dagss@1026 | 13 NPY_SHORT, NPY_USHORT,
|
| dagss@1026 | 14 NPY_INT, NPY_UINT,
|
| dagss@1026 | 15 NPY_LONG, NPY_ULONG,
|
| dagss@1026 | 16 NPY_LONGLONG, NPY_ULONGLONG,
|
| dagss@1026 | 17 NPY_FLOAT, NPY_DOUBLE, NPY_LONGDOUBLE,
|
| dagss@1026 | 18 NPY_CFLOAT, NPY_CDOUBLE, NPY_CLONGDOUBLE,
|
| dagss@1026 | 19 NPY_OBJECT,
|
| dagss@1026 | 20 NPY_STRING, NPY_UNICODE,
|
| dagss@1026 | 21 NPY_VOID,
|
| dagss@1026 | 22 NPY_NTYPES,
|
| dagss@1026 | 23 NPY_NOTYPE,
|
| dagss@1026 | 24 NPY_CHAR,
|
| dagss@1154 | 25 NPY_USERDEF,
|
| dagss@1154 | 26
|
| dagss@1154 | 27 NPY_C_CONTIGUOUS,
|
| dagss@1154 | 28 NPY_F_CONTIGUOUS
|
| dagss@1154 | 29
|
| dagss@1235 | 30 ctypedef class numpy.dtype [object PyArray_Descr]:
|
| dagss@1235 | 31 cdef int type_num
|
| dagss@1235 | 32 cdef object fields
|
| dagss@1235 | 33 cdef object names
|
| dagss@1235 | 34
|
| dagss@980 | 35
|
| dagss@778 | 36 ctypedef class numpy.ndarray [object PyArrayObject]:
|
| dagss@1026 | 37 cdef __cythonbufferdefaults__ = {"mode": "strided"}
|
| dagss@1026 | 38
|
| dagss@968 | 39 cdef:
|
| dagss@968 | 40 char *data
|
| dagss@1026 | 41 int ndim "nd"
|
| dagss@1026 | 42 npy_intp *shape "dimensions"
|
| dagss@980 | 43 npy_intp *strides
|
| dagss@1154 | 44 int flags
|
| dagss@1235 | 45 dtype descr
|
| dagss@968 | 46
|
| dagss@1026 | 47 # Note: This syntax (function definition in pxd files) is an
|
| dagss@1026 | 48 # experimental exception made for __getbuffer__ and __releasebuffer__
|
| dagss@1026 | 49 # -- the details of this may change.
|
| dagss@980 | 50 def __getbuffer__(ndarray self, Py_buffer* info, int flags):
|
| dagss@1026 | 51 # This implementation of getbuffer is geared towards Cython
|
| dagss@1154 | 52 # requirements, and does not yet fullfill the PEP.
|
| dagss@1154 | 53 # In particular strided access is always provided regardless
|
| dagss@1154 | 54 # of flags
|
| dagss@1328 | 55 cdef int copy_shape, i, ndim
|
| dagss@1328 | 56 ndim = PyArray_NDIM(self)
|
| dagss@1328 | 57
|
| dagss@980 | 58 if sizeof(npy_intp) != sizeof(Py_ssize_t):
|
| david@1327 | 59 copy_shape = 1
|
| david@1327 | 60 else:
|
| david@1327 | 61 copy_shape = 0
|
| dagss@980 | 62
|
| dagss@1154 | 63 if ((flags & pybuf.PyBUF_C_CONTIGUOUS == pybuf.PyBUF_C_CONTIGUOUS)
|
| dagss@1154 | 64 and not PyArray_CHKFLAGS(self, NPY_C_CONTIGUOUS)):
|
| dagss@1154 | 65 raise ValueError("ndarray is not C contiguous")
|
| dagss@1154 | 66
|
| dagss@1154 | 67 if ((flags & pybuf.PyBUF_F_CONTIGUOUS == pybuf.PyBUF_F_CONTIGUOUS)
|
| dagss@1154 | 68 and not PyArray_CHKFLAGS(self, NPY_F_CONTIGUOUS)):
|
| dagss@1154 | 69 raise ValueError("ndarray is not Fortran contiguous")
|
| dagss@1154 | 70
|
| dagss@1026 | 71 info.buf = PyArray_DATA(self)
|
| dagss@1328 | 72 info.ndim = ndim
|
| david@1327 | 73 if copy_shape:
|
| dagss@1328 | 74 # Allocate new buffer for strides and shape info. This is allocated
|
| dagss@1328 | 75 # as one block, strides first.
|
| dagss@1328 | 76 info.strides = <Py_ssize_t*>stdlib.malloc(sizeof(Py_ssize_t) * ndim * 2)
|
| dagss@1328 | 77 info.shape = info.strides + ndim
|
| dagss@1328 | 78 for i in range(ndim):
|
| david@1327 | 79 info.strides[i] = PyArray_STRIDES(self)[i]
|
| david@1327 | 80 info.shape[i] = PyArray_DIMS(self)[i]
|
| david@1327 | 81 else:
|
| david@1327 | 82 info.strides = <Py_ssize_t*>PyArray_STRIDES(self)
|
| david@1327 | 83 info.shape = <Py_ssize_t*>PyArray_DIMS(self)
|
| dagss@980 | 84 info.suboffsets = NULL
|
| dagss@1026 | 85 info.itemsize = PyArray_ITEMSIZE(self)
|
| dagss@980 | 86 info.readonly = not PyArray_ISWRITEABLE(self)
|
| dagss@1026 | 87
|
| dagss@1235 | 88 cdef int t
|
| dagss@1235 | 89 cdef char* f = NULL
|
| dagss@1235 | 90 cdef dtype descr = self.descr
|
| dagss@1235 | 91 cdef list stack
|
| dagss@1026 | 92
|
| dagss@1235 | 93 cdef bint hasfields = PyDataType_HASFIELDS(descr)
|
| dagss@1235 | 94
|
| dagss@1235 | 95 # Ugly hack warning:
|
| dagss@1235 | 96 # Cython currently will not support helper functions in
|
| dagss@1235 | 97 # pxd files -- so we must keep our own, manual stack!
|
| dagss@1235 | 98 # In addition, avoid allocation of the stack in the common
|
| dagss@1235 | 99 # case that we are dealing with a single non-nested datatype...
|
| dagss@1235 | 100 # (this would look much prettier if we could use utility
|
| dagss@1235 | 101 # functions).
|
| dagss@1235 | 102
|
| david@1327 | 103 if not hasfields and not copy_shape:
|
| david@1327 | 104 # do not call releasebuffer
|
| david@1327 | 105 info.obj = None
|
| david@1327 | 106 else:
|
| david@1327 | 107 # need to call releasebuffer
|
| david@1327 | 108 info.obj = self
|
| david@1327 | 109
|
| dagss@1235 | 110 if not hasfields:
|
| dagss@1235 | 111 t = descr.type_num
|
| dagss@1235 | 112 if t == NPY_BYTE: f = "b"
|
| dagss@1235 | 113 elif t == NPY_UBYTE: f = "B"
|
| dagss@1235 | 114 elif t == NPY_SHORT: f = "h"
|
| dagss@1235 | 115 elif t == NPY_USHORT: f = "H"
|
| dagss@1235 | 116 elif t == NPY_INT: f = "i"
|
| dagss@1235 | 117 elif t == NPY_UINT: f = "I"
|
| dagss@1235 | 118 elif t == NPY_LONG: f = "l"
|
| dagss@1235 | 119 elif t == NPY_ULONG: f = "L"
|
| dagss@1235 | 120 elif t == NPY_LONGLONG: f = "q"
|
| dagss@1235 | 121 elif t == NPY_ULONGLONG: f = "Q"
|
| dagss@1235 | 122 elif t == NPY_FLOAT: f = "f"
|
| dagss@1235 | 123 elif t == NPY_DOUBLE: f = "d"
|
| dagss@1235 | 124 elif t == NPY_LONGDOUBLE: f = "g"
|
| dagss@1235 | 125 elif t == NPY_CFLOAT: f = "Zf"
|
| dagss@1235 | 126 elif t == NPY_CDOUBLE: f = "Zd"
|
| dagss@1235 | 127 elif t == NPY_CLONGDOUBLE: f = "Zg"
|
| dagss@1235 | 128 elif t == NPY_OBJECT: f = "O"
|
| dagss@1235 | 129 else:
|
| dagss@1235 | 130 raise ValueError("unknown dtype code in numpy.pxd (%d)" % t)
|
| dagss@1235 | 131 info.format = f
|
| dagss@1235 | 132 return
|
| dagss@1235 | 133 else:
|
| dagss@1235 | 134 info.format = <char*>stdlib.malloc(255) # static size
|
| dagss@1410 | 135 f = _util_dtypestring(descr, info.format, info.format + 255)
|
| dagss@1410 | 136 f[0] = 0 # Terminate format string
|
| dagss@1235 | 137
|
| dagss@1235 | 138 def __releasebuffer__(ndarray self, Py_buffer* info):
|
| dagss@1330 | 139 if PyArray_HASFIELDS(self):
|
| dagss@1330 | 140 stdlib.free(info.format)
|
| david@1327 | 141 if sizeof(npy_intp) != sizeof(Py_ssize_t):
|
| david@1327 | 142 stdlib.free(info.strides)
|
| dagss@1328 | 143 # info.shape was stored after info.strides in the same block
|
| robertwb@1023 | 144
|
| robertwb@1023 | 145
|
| dagss@1026 | 146 cdef void* PyArray_DATA(ndarray arr)
|
| dagss@1026 | 147 cdef int PyArray_TYPE(ndarray arr)
|
| dagss@1026 | 148 cdef int PyArray_NDIM(ndarray arr)
|
| dagss@1026 | 149 cdef int PyArray_ISWRITEABLE(ndarray arr)
|
| dalcinl@1252 | 150 cdef npy_intp* PyArray_STRIDES(ndarray arr)
|
| dalcinl@1252 | 151 cdef npy_intp* PyArray_DIMS(ndarray arr)
|
| dalcinl@1252 | 152 cdef int PyArray_ITEMSIZE(ndarray arr)
|
| dagss@1154 | 153 cdef int PyArray_CHKFLAGS(ndarray arr, int flags)
|
| dagss@1330 | 154 cdef int PyArray_HASFIELDS(ndarray arr)
|
| dagss@1235 | 155
|
| dagss@1235 | 156 cdef int PyDataType_HASFIELDS(dtype obj)
|
| robertwb@1023 | 157
|
| dagss@1043 | 158 ctypedef signed int npy_byte
|
| dagss@1043 | 159 ctypedef signed int npy_short
|
| dagss@1043 | 160 ctypedef signed int npy_int
|
| dagss@1043 | 161 ctypedef signed int npy_long
|
| dagss@1043 | 162 ctypedef signed int npy_longlong
|
| dagss@1043 | 163
|
| dagss@1043 | 164 ctypedef unsigned int npy_ubyte
|
| dagss@1043 | 165 ctypedef unsigned int npy_ushort
|
| dagss@1043 | 166 ctypedef unsigned int npy_uint
|
| dagss@1043 | 167 ctypedef unsigned int npy_ulong
|
| dagss@1043 | 168 ctypedef unsigned int npy_ulonglong
|
| dagss@1043 | 169
|
| dagss@1043 | 170 ctypedef float npy_float
|
| dagss@1043 | 171 ctypedef float npy_double
|
| dagss@1043 | 172 ctypedef float npy_longdouble
|
| dagss@1043 | 173
|
| dagss@1026 | 174 ctypedef signed int npy_int8
|
| dagss@1026 | 175 ctypedef signed int npy_int16
|
| dagss@1026 | 176 ctypedef signed int npy_int32
|
| dagss@1026 | 177 ctypedef signed int npy_int64
|
| dagss@1026 | 178 ctypedef signed int npy_int96
|
| dagss@1026 | 179 ctypedef signed int npy_int128
|
| dagss@778 | 180
|
| dagss@778 | 181 ctypedef unsigned int npy_uint8
|
| dagss@778 | 182 ctypedef unsigned int npy_uint16
|
| dagss@778 | 183 ctypedef unsigned int npy_uint32
|
| dagss@778 | 184 ctypedef unsigned int npy_uint64
|
| dagss@778 | 185 ctypedef unsigned int npy_uint96
|
| dagss@778 | 186 ctypedef unsigned int npy_uint128
|
| dagss@778 | 187
|
| dagss@778 | 188 ctypedef float npy_float32
|
| dagss@778 | 189 ctypedef float npy_float64
|
| dagss@778 | 190 ctypedef float npy_float80
|
| dagss@778 | 191 ctypedef float npy_float96
|
| dagss@778 | 192 ctypedef float npy_float128
|
| dagss@778 | 193
|
| dagss@1329 | 194 ctypedef struct npy_cfloat:
|
| dagss@1329 | 195 float real
|
| dagss@1329 | 196 float imag
|
| dagss@1329 | 197
|
| dagss@1329 | 198 ctypedef struct npy_cdouble:
|
| dagss@1329 | 199 double real
|
| dagss@1329 | 200 double imag
|
| dagss@1329 | 201
|
| dagss@1329 | 202 ctypedef struct npy_clongdouble:
|
| dagss@1329 | 203 long double real
|
| dagss@1329 | 204 long double imag
|
| dagss@1329 | 205
|
| dagss@1043 | 206 # Typedefs that matches the runtime dtype objects in
|
| dagss@1043 | 207 # the numpy module.
|
| dagss@1042 | 208
|
| dagss@1043 | 209 # The ones that are commented out needs an IFDEF function
|
| dagss@1043 | 210 # in Cython to enable them only on the right systems.
|
| dagss@1042 | 211
|
| dagss@1043 | 212 ctypedef npy_int8 int8_t
|
| dagss@1043 | 213 ctypedef npy_int16 int16_t
|
| dagss@1043 | 214 ctypedef npy_int32 int32_t
|
| dagss@1043 | 215 ctypedef npy_int64 int64_t
|
| dagss@1043 | 216 #ctypedef npy_int96 int96_t
|
| dagss@1043 | 217 #ctypedef npy_int128 int128_t
|
| dagss@1042 | 218
|
| dagss@1043 | 219 ctypedef npy_uint8 uint8_t
|
| dagss@1043 | 220 ctypedef npy_uint16 uint16_t
|
| dagss@1043 | 221 ctypedef npy_uint32 uint32_t
|
| dagss@1043 | 222 ctypedef npy_uint64 uint64_t
|
| dagss@1043 | 223 #ctypedef npy_uint96 uint96_t
|
| dagss@1043 | 224 #ctypedef npy_uint128 uint128_t
|
| dagss@1043 | 225
|
| dagss@1043 | 226 ctypedef npy_float32 float32_t
|
| dagss@1043 | 227 ctypedef npy_float64 float64_t
|
| dagss@1043 | 228 #ctypedef npy_float80 float80_t
|
| dagss@1043 | 229 #ctypedef npy_float128 float128_t
|
| dagss@1043 | 230
|
| dagss@1043 | 231 # The int types are mapped a bit surprising --
|
| dagss@1043 | 232 # numpy.int corresponds to 'l' and numpy.long to 'q'
|
| dagss@1043 | 233 ctypedef npy_long int_t
|
| dagss@1043 | 234 ctypedef npy_longlong long_t
|
| dagss@1043 | 235
|
| dagss@1043 | 236 ctypedef npy_ulong uint_t
|
| dagss@1043 | 237 ctypedef npy_ulonglong ulong_t
|
| dagss@1043 | 238
|
| dagss@1329 | 239 ctypedef npy_double float_t
|
| dagss@1043 | 240 ctypedef npy_double double_t
|
| dagss@1043 | 241 ctypedef npy_longdouble longdouble_t
|
| dagss@1043 | 242
|
| dagss@1329 | 243 ctypedef npy_cfloat cfloat_t
|
| dagss@1329 | 244 ctypedef npy_cdouble cdouble_t
|
| dagss@1329 | 245 ctypedef npy_clongdouble clongdouble_t
|
| dagss@1410 | 246
|
| dagss@1410 | 247
|
| dagss@1410 | 248 cdef inline char* _util_dtypestring(dtype descr, char* f, char* end) except NULL:
|
| dagss@1410 | 249 # Recursive utility function used in __getbuffer__ to get format
|
| dagss@1410 | 250 # string. The new location in the format string is returned.
|
| dagss@1410 | 251
|
| dagss@1410 | 252 cdef dtype child
|
| dagss@1410 | 253 cdef tuple i
|
| dagss@1410 | 254 for i in descr.fields.itervalues():
|
| dagss@1410 | 255 child = i[0]
|
| dagss@1410 | 256 if not PyDataType_HASFIELDS(child):
|
| dagss@1410 | 257 t = child.type_num
|
| dagss@1410 | 258 if end - f < 15: # this should leave room for "T{" and "}" as well
|
| dagss@1410 | 259 raise RuntimeError("Format string allocated too short.")
|
| dagss@1410 | 260
|
| dagss@1410 | 261 # Until ticket #99 is fixed, use integers to avoid warnings
|
| dagss@1410 | 262 if t == NPY_BYTE: f[0] = 98 #"b"
|
| dagss@1410 | 263 elif t == NPY_UBYTE: f[0] = 66 #"B"
|
| dagss@1410 | 264 elif t == NPY_SHORT: f[0] = 104 #"h"
|
| dagss@1410 | 265 elif t == NPY_USHORT: f[0] = 72 #"H"
|
| dagss@1410 | 266 elif t == NPY_INT: f[0] = 105 #"i"
|
| dagss@1410 | 267 elif t == NPY_UINT: f[0] = 73 #"I"
|
| dagss@1410 | 268 elif t == NPY_LONG: f[0] = 108 #"l"
|
| dagss@1410 | 269 elif t == NPY_ULONG: f[0] = 76 #"L"
|
| dagss@1410 | 270 elif t == NPY_LONGLONG: f[0] = 113 #"q"
|
| dagss@1410 | 271 elif t == NPY_ULONGLONG: f[0] = 81 #"Q"
|
| dagss@1410 | 272 elif t == NPY_FLOAT: f[0] = 102 #"f"
|
| dagss@1410 | 273 elif t == NPY_DOUBLE: f[0] = 100 #"d"
|
| dagss@1410 | 274 elif t == NPY_LONGDOUBLE: f[0] = 103 #"g"
|
| dagss@1410 | 275 elif t == NPY_CFLOAT: f[0] = 90; f[1] = 102; f += 1
|
| dagss@1410 | 276 elif t == NPY_CDOUBLE: f[0] = 90; f[1] = 100; f += 1
|
| dagss@1410 | 277 elif t == NPY_CLONGDOUBLE: f[0] = 90; f[1] = 103; f += 1
|
| dagss@1410 | 278 elif t == NPY_OBJECT: f[0] = 79 #"O"
|
| dagss@1410 | 279 else:
|
| dagss@1410 | 280 raise ValueError("unknown dtype code in numpy.pxd (%d)" % t)
|
| dagss@1410 | 281 f += 1
|
| dagss@1410 | 282 else:
|
| dagss@1410 | 283 f[0] = 84 #"T"
|
| dagss@1410 | 284 f[1] = 123 #"{"
|
| dagss@1410 | 285 f += 2
|
| dagss@1410 | 286 f = _util_dtypestring(child, f, end)
|
| dagss@1410 | 287 f[0] = 125 #"}"
|
| dagss@1410 | 288 f += 1
|
| dagss@1410 | 289 return f
|
| dagss@1410 | 290
|