array.pxd 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. """
  2. array.pxd
  3. Cython interface to Python's array.array module.
  4. * 1D contiguous data view
  5. * tools for fast array creation, maximum C-speed and handiness
  6. * suitable as allround light weight auto-array within Cython code too
  7. Usage:
  8. >>> cimport array
  9. Usage through Cython buffer interface (Py2.3+):
  10. >>> def f(arg1, unsigned i, double dx)
  11. ... array.array[double] a = arg1
  12. ... a[i] += dx
  13. Fast C-level new_array(_zeros), resize_array, copy_array, Py_SIZE(obj),
  14. zero_array
  15. cdef array.array[double] k = array.copy(d)
  16. cdef array.array[double] n = array.array(d, Py_SIZE(d) * 2 )
  17. cdef array.array[double] m = array.zeros_like(FLOAT_TEMPLATE)
  18. array.resize(f, 200000)
  19. Zero overhead with naked data pointer views by union:
  20. _f, _d, _i, _c, _u, ...
  21. => Original C array speed + Python dynamic memory management
  22. cdef array.array a = inarray
  23. if
  24. a._d[2] += 0.66 # use as double array without extra casting
  25. float *subview = vector._f + 10 # starting from 10th element
  26. unsigned char *subview_buffer = vector._B + 4
  27. Suitable as lightweight arrays intra Cython without speed penalty.
  28. Replacement for C stack/malloc arrays; no trouble with refcounting,
  29. mem.leaks; seamless Python compatibility, buffer() optional
  30. last changes: 2009-05-15 rk
  31. : 2009-12-06 bp
  32. : 2012-05-02 andreasvc
  33. : (see revision control)
  34. """
  35. from libc.string cimport strcat, strncat, \
  36. memset, memchr, memcmp, memcpy, memmove
  37. from cpython.object cimport Py_SIZE
  38. from cpython.ref cimport PyTypeObject, Py_TYPE
  39. from cpython.exc cimport PyErr_BadArgument
  40. from cpython.mem cimport PyObject_Malloc, PyObject_Free
  41. cdef extern from *: # Hard-coded utility code hack.
  42. ctypedef class array.array [object arrayobject]
  43. ctypedef object GETF(array a, Py_ssize_t ix)
  44. ctypedef object SETF(array a, Py_ssize_t ix, object o)
  45. ctypedef struct arraydescr: # [object arraydescr]:
  46. char typecode
  47. int itemsize
  48. GETF getitem # PyObject * (*getitem)(struct arrayobject *, Py_ssize_t);
  49. SETF setitem # int (*setitem)(struct arrayobject *, Py_ssize_t, PyObject *);
  50. ctypedef union __data_union:
  51. # views of ob_item:
  52. float* as_floats # direct float pointer access to buffer
  53. double* as_doubles # double ...
  54. int* as_ints
  55. unsigned int *as_uints
  56. unsigned char *as_uchars
  57. signed char *as_schars
  58. char *as_chars
  59. unsigned long *as_ulongs
  60. long *as_longs
  61. unsigned long long *as_ulonglongs
  62. long long *as_longlongs
  63. short *as_shorts
  64. unsigned short *as_ushorts
  65. Py_UNICODE *as_pyunicodes
  66. void *as_voidptr
  67. ctypedef class array.array [object arrayobject]:
  68. cdef __cythonbufferdefaults__ = {'ndim' : 1, 'mode':'c'}
  69. cdef:
  70. Py_ssize_t ob_size
  71. arraydescr* ob_descr # struct arraydescr *ob_descr;
  72. __data_union data
  73. def __getbuffer__(self, Py_buffer* info, int flags):
  74. # This implementation of getbuffer is geared towards Cython
  75. # requirements, and does not yet fulfill the PEP.
  76. # In particular strided access is always provided regardless
  77. # of flags
  78. item_count = Py_SIZE(self)
  79. info.suboffsets = NULL
  80. info.buf = self.data.as_chars
  81. info.readonly = 0
  82. info.ndim = 1
  83. info.itemsize = self.ob_descr.itemsize # e.g. sizeof(float)
  84. info.len = info.itemsize * item_count
  85. info.shape = <Py_ssize_t*> PyObject_Malloc(sizeof(Py_ssize_t) + 2)
  86. if not info.shape:
  87. raise MemoryError()
  88. info.shape[0] = item_count # constant regardless of resizing
  89. info.strides = &info.itemsize
  90. info.format = <char*> (info.shape + 1)
  91. info.format[0] = self.ob_descr.typecode
  92. info.format[1] = 0
  93. info.obj = self
  94. def __releasebuffer__(self, Py_buffer* info):
  95. PyObject_Free(info.shape)
  96. array newarrayobject(PyTypeObject* type, Py_ssize_t size, arraydescr *descr)
  97. # fast resize/realloc
  98. # not suitable for small increments; reallocation 'to the point'
  99. int resize(array self, Py_ssize_t n) except -1
  100. # efficient for small increments (not in Py2.3-)
  101. int resize_smart(array self, Py_ssize_t n) except -1
  102. cdef inline array clone(array template, Py_ssize_t length, bint zero):
  103. """ fast creation of a new array, given a template array.
  104. type will be same as template.
  105. if zero is true, new array will be initialized with zeroes."""
  106. cdef array op = newarrayobject(Py_TYPE(template), length, template.ob_descr)
  107. if zero and op is not None:
  108. memset(op.data.as_chars, 0, length * op.ob_descr.itemsize)
  109. return op
  110. cdef inline array copy(array self):
  111. """ make a copy of an array. """
  112. cdef array op = newarrayobject(Py_TYPE(self), Py_SIZE(self), self.ob_descr)
  113. memcpy(op.data.as_chars, self.data.as_chars, Py_SIZE(op) * op.ob_descr.itemsize)
  114. return op
  115. cdef inline int extend_buffer(array self, char* stuff, Py_ssize_t n) except -1:
  116. """ efficient appending of new stuff of same type
  117. (e.g. of same array type)
  118. n: number of elements (not number of bytes!) """
  119. cdef Py_ssize_t itemsize = self.ob_descr.itemsize
  120. cdef Py_ssize_t origsize = Py_SIZE(self)
  121. resize_smart(self, origsize + n)
  122. memcpy(self.data.as_chars + origsize * itemsize, stuff, n * itemsize)
  123. return 0
  124. cdef inline int extend(array self, array other) except -1:
  125. """ extend array with data from another array; types must match. """
  126. if self.ob_descr.typecode != other.ob_descr.typecode:
  127. PyErr_BadArgument()
  128. return extend_buffer(self, other.data.as_chars, Py_SIZE(other))
  129. cdef inline void zero(array self):
  130. """ set all elements of array to zero. """
  131. memset(self.data.as_chars, 0, Py_SIZE(self) * self.ob_descr.itemsize)