NPY_NO_EXPORT int _IsAligned(PyArrayObject *ap) { unsigned int i, aligned = 1; const unsigned int alignment = PyArray_DESCR(ap)->alignment; /* The special casing for STRING and VOID types was removed * in accordance with http://projects.scipy.org/numpy/ticket/1227 * It used to be that IsAligned always returned True for these * types, which is indeed the case when they are created using * PyArray_DescrConverter(), but not necessarily when using * PyArray_DescrAlignConverter(). */ if (alignment == 1) { return 1; } aligned = npy_is_aligned(PyArray_DATA(ap), alignment); for (i = 0; i < PyArray_NDIM(ap); i++) { #if NPY_RELAXED_STRIDES_CHECKING if (PyArray_DIM(ap, i) > 1) { /* if shape[i] == 1, the stride is never used */ aligned &= npy_is_aligned((void*)PyArray_STRIDES(ap)[i], alignment); } else if (PyArray_DIM(ap, i) == 0) { /* an array with zero elements is always aligned */ return 1; } #else /* not NPY_RELAXED_STRIDES_CHECKING */ aligned &= npy_is_aligned((void*)PyArray_STRIDES(ap)[i], alignment); #endif /* not NPY_RELAXED_STRIDES_CHECKING */ } return aligned != 0; }
/* 0-strided arrays are not contiguous (even if dimension == 1) */ static int _IsFortranContiguous(PyArrayObject *ap) { npy_intp sd; npy_intp dim; int i; if (PyArray_NDIM(ap) == 0) { return 1; } sd = PyArray_DESCR(ap)->elsize; if (PyArray_NDIM(ap) == 1) { return PyArray_DIMS(ap)[0] == 1 || sd == PyArray_STRIDES(ap)[0]; } for (i = 0; i < PyArray_NDIM(ap); ++i) { dim = PyArray_DIMS(ap)[i]; /* fortran contiguous by definition */ if (dim == 0) { return 1; } if (PyArray_STRIDES(ap)[i] != sd) { return 0; } sd *= dim; } return 1; }
NPY_NO_EXPORT int _IsAligned(PyArrayObject *ap) { unsigned int i; npy_uintp aligned; npy_uintp alignment = PyArray_DESCR(ap)->alignment; /* alignment 1 types should have a efficient alignment for copy loops */ if (PyArray_ISFLEXIBLE(ap) || PyArray_ISSTRING(ap)) { alignment = 16; } if (alignment == 1) { return 1; } aligned = (npy_uintp)PyArray_DATA(ap); for (i = 0; i < PyArray_NDIM(ap); i++) { #if NPY_RELAXED_STRIDES_CHECKING /* skip dim == 1 as it is not required to have stride 0 */ if (PyArray_DIM(ap, i) > 1) { /* if shape[i] == 1, the stride is never used */ aligned |= (npy_uintp)PyArray_STRIDES(ap)[i]; } else if (PyArray_DIM(ap, i) == 0) { /* an array with zero elements is always aligned */ return 1; } #else /* not NPY_RELAXED_STRIDES_CHECKING */ aligned |= (npy_uintp)PyArray_STRIDES(ap)[i]; #endif /* not NPY_RELAXED_STRIDES_CHECKING */ } return npy_is_aligned((void *)aligned, alignment); }
PyObject* r2k(PyObject *self, PyObject *args) { Py_complex alpha; PyArrayObject* a; PyArrayObject* b; double beta; PyArrayObject* c; if (!PyArg_ParseTuple(args, "DOOdO", &alpha, &a, &b, &beta, &c)) return NULL; int n = PyArray_DIMS(a)[0]; int k = PyArray_DIMS(a)[1]; for (int d = 2; d < PyArray_NDIM(a); d++) k *= PyArray_DIMS(a)[d]; int ldc = PyArray_STRIDES(c)[0] / PyArray_STRIDES(c)[1]; if (PyArray_DESCR(a)->type_num == NPY_DOUBLE) dsyr2k_("u", "t", &n, &k, (double*)(&alpha), DOUBLEP(a), &k, DOUBLEP(b), &k, &beta, DOUBLEP(c), &ldc); else zher2k_("u", "c", &n, &k, (void*)(&alpha), (void*)COMPLEXP(a), &k, (void*)COMPLEXP(b), &k, &beta, (void*)COMPLEXP(c), &ldc); Py_RETURN_NONE; }
PyObject* gemm(PyObject *self, PyObject *args) { Py_complex alpha; PyArrayObject* a; PyArrayObject* b; Py_complex beta; PyArrayObject* c; char transa = 'n'; if (!PyArg_ParseTuple(args, "DOODO|c", &alpha, &a, &b, &beta, &c, &transa)) return NULL; int m, k, lda, ldb, ldc; if (transa == 'n') { m = PyArray_DIMS(a)[1]; for (int i = 2; i < PyArray_NDIM(a); i++) m *= PyArray_DIMS(a)[i]; k = PyArray_DIMS(a)[0]; lda = MAX(1, PyArray_STRIDES(a)[0] / PyArray_STRIDES(a)[PyArray_NDIM(a) - 1]); ldb = MAX(1, PyArray_STRIDES(b)[0] / PyArray_STRIDES(b)[1]); ldc = MAX(1, PyArray_STRIDES(c)[0] / PyArray_STRIDES(c)[PyArray_NDIM(c) - 1]); } else { k = PyArray_DIMS(a)[1]; for (int i = 2; i < PyArray_NDIM(a); i++) k *= PyArray_DIMS(a)[i]; m = PyArray_DIMS(a)[0]; lda = MAX(1, k); ldb = MAX(1, PyArray_STRIDES(b)[0] / PyArray_STRIDES(b)[PyArray_NDIM(b) - 1]); ldc = MAX(1, PyArray_STRIDES(c)[0] / PyArray_STRIDES(c)[1]); } int n = PyArray_DIMS(b)[0]; if (PyArray_DESCR(a)->type_num == NPY_DOUBLE) dgemm_(&transa, "n", &m, &n, &k, &(alpha.real), DOUBLEP(a), &lda, DOUBLEP(b), &ldb, &(beta.real), DOUBLEP(c), &ldc); else zgemm_(&transa, "n", &m, &n, &k, &alpha, (void*)COMPLEXP(a), &lda, (void*)COMPLEXP(b), &ldb, &beta, (void*)COMPLEXP(c), &ldc); Py_RETURN_NONE; }
PyObject * gdkpixbuf_get_pixels_array(PyObject *pixbuf_pyobject) { GdkPixbuf *pixbuf = GDK_PIXBUF(((PyGObject *)pixbuf_pyobject)->obj); PyArrayObject *array; npy_intp dims[3] = { 0, 0, 3 }; dims[0] = gdk_pixbuf_get_height(pixbuf); dims[1] = gdk_pixbuf_get_width(pixbuf); if (gdk_pixbuf_get_has_alpha(pixbuf)) dims[2] = 4; guchar *pixels = gdk_pixbuf_get_pixels(pixbuf); array = (PyArrayObject *)PyArray_SimpleNewFromData(3, dims, NPY_UBYTE, pixels); if (array == NULL) return NULL; PyArray_STRIDES(array)[0] = gdk_pixbuf_get_rowstride(pixbuf); // the array holds a ref to the pixbuf pixels through this wrapper Py_INCREF(pixbuf_pyobject); #ifdef NPY_1_7_API_VERSION PyArray_SetBaseObject(array, (PyObject *)pixbuf_pyobject); #else array->base = (PyObject *)pixbuf_pyobject; #endif return PyArray_Return(array); }
NPY_NO_EXPORT int IsAligned(PyArrayObject *ap) { return raw_array_is_aligned(PyArray_NDIM(ap), PyArray_DIMS(ap), PyArray_DATA(ap), PyArray_STRIDES(ap), PyArray_DESCR(ap)->alignment); }
/* Gets a half-open range [start, end) which contains the array data */ NPY_NO_EXPORT void get_array_memory_extents(PyArrayObject *arr, npy_uintp *out_start, npy_uintp *out_end) { npy_uintp start, end; npy_intp idim, ndim = PyArray_NDIM(arr); npy_intp *dimensions = PyArray_DIMS(arr), *strides = PyArray_STRIDES(arr); /* Calculate with a closed range [start, end] */ start = end = (npy_uintp)PyArray_DATA(arr); for (idim = 0; idim < ndim; ++idim) { npy_intp stride = strides[idim], dim = dimensions[idim]; /* If the array size is zero, return an empty range */ if (dim == 0) { *out_start = *out_end = (npy_uintp)PyArray_DATA(arr); return; } /* Expand either upwards or downwards depending on stride */ else { if (stride > 0) { end += stride*(dim-1); } else if (stride < 0) { start += stride*(dim-1); } } } /* Return a half-open range */ *out_start = start; *out_end = end + PyArray_DESCR(arr)->elsize; }
NPY_NO_EXPORT int IsUintAligned(PyArrayObject *ap) { return raw_array_is_aligned(PyArray_NDIM(ap), PyArray_DIMS(ap), PyArray_DATA(ap), PyArray_STRIDES(ap), npy_uint_alignment(PyArray_DESCR(ap)->elsize)); }
int getStrides( void* arr, int* strides ) { npy_intp* np_dims = PyArray_STRIDES( arr ); int i; for( i=0; i<getNDim( arr ); i++ ) { strides[i] = (int)np_dims[i]; } return 0; }
NPY_NO_EXPORT int _IsAligned(PyArrayObject *ap) { unsigned int i; npy_uintp aligned; npy_uintp alignment = PyArray_DESCR(ap)->alignment; /* alignment 1 types should have a efficient alignment for copy loops */ if (PyArray_ISFLEXIBLE(ap) || PyArray_ISSTRING(ap)) { npy_intp itemsize = PyArray_ITEMSIZE(ap); /* power of two sizes may be loaded in larger moves */ if (((itemsize & (itemsize - 1)) == 0)) { alignment = itemsize > NPY_MAX_COPY_ALIGNMENT ? NPY_MAX_COPY_ALIGNMENT : itemsize; } else { /* if not power of two it will be accessed bytewise */ alignment = 1; } } if (alignment == 1) { return 1; } aligned = (npy_uintp)PyArray_DATA(ap); for (i = 0; i < PyArray_NDIM(ap); i++) { #if NPY_RELAXED_STRIDES_CHECKING /* skip dim == 1 as it is not required to have stride 0 */ if (PyArray_DIM(ap, i) > 1) { /* if shape[i] == 1, the stride is never used */ aligned |= (npy_uintp)PyArray_STRIDES(ap)[i]; } else if (PyArray_DIM(ap, i) == 0) { /* an array with zero elements is always aligned */ return 1; } #else /* not NPY_RELAXED_STRIDES_CHECKING */ aligned |= (npy_uintp)PyArray_STRIDES(ap)[i]; #endif /* not NPY_RELAXED_STRIDES_CHECKING */ } return npy_is_aligned((void *)aligned, alignment); }
PyObject* gemv(PyObject *self, PyObject *args) { Py_complex alpha; PyArrayObject* a; PyArrayObject* x; Py_complex beta; PyArrayObject* y; char trans = 't'; if (!PyArg_ParseTuple(args, "DOODO|c", &alpha, &a, &x, &beta, &y, &trans)) return NULL; int m, n, lda, itemsize, incx, incy; if (trans == 'n') { m = PyArray_DIMS(a)[1]; for (int i = 2; i < PyArray_NDIM(a); i++) m *= PyArray_DIMS(a)[i]; n = PyArray_DIMS(a)[0]; lda = MAX(1, m); } else { n = PyArray_DIMS(a)[0]; for (int i = 1; i < PyArray_NDIM(a)-1; i++) n *= PyArray_DIMS(a)[i]; m = PyArray_DIMS(a)[PyArray_NDIM(a)-1]; lda = MAX(1, m); } if (PyArray_DESCR(a)->type_num == NPY_DOUBLE) itemsize = sizeof(double); else itemsize = sizeof(double_complex); incx = PyArray_STRIDES(x)[0]/itemsize; incy = 1; if (PyArray_DESCR(a)->type_num == NPY_DOUBLE) dgemv_(&trans, &m, &n, &(alpha.real), DOUBLEP(a), &lda, DOUBLEP(x), &incx, &(beta.real), DOUBLEP(y), &incy); else zgemv_(&trans, &m, &n, &alpha, (void*)COMPLEXP(a), &lda, (void*)COMPLEXP(x), &incx, &beta, (void*)COMPLEXP(y), &incy); Py_RETURN_NONE; }
UMatData* allocate(PyObject* o, int dims, const int* sizes, int type, size_t* step) const { UMatData* u = new UMatData(this); u->data = u->origdata = (uchar*) PyArray_DATA((PyArrayObject*) o); npy_intp* _strides = PyArray_STRIDES((PyArrayObject*) o); for (int i = 0; i < dims - 1; i++) step[i] = (size_t) _strides[i]; step[dims - 1] = CV_ELEM_SIZE(type); u->size = sizes[0] * step[0]; u->userdata = o; return u; }
void local_histogram(double* H, unsigned int clamp, PyArrayIterObject* iter, const unsigned int* size) { PyArrayObject *block, *im = iter->ao; PyArrayIterObject* block_iter; unsigned int i, left, right, center, halfsize, dim, offset=0; npy_intp block_dims[3]; UPDATE_ITERATOR_COORDS(iter); /* Compute block corners */ for (i=0; i<3; i++) { center = iter->coordinates[i]; halfsize = size[i]/2; dim = PyArray_DIM(im, i); /* Left handside corner */ if (center<halfsize) left = 0; else left = center-halfsize; /* Right handside corner (plus one)*/ right = center+halfsize+1; if (right>dim) right = dim; /* Block properties */ offset += left*PyArray_STRIDE(im, i); block_dims[i] = right-left; } /* Create the block as a vew and the block iterator */ block = (PyArrayObject*)PyArray_New(&PyArray_Type, 3, block_dims, PyArray_TYPE(im), PyArray_STRIDES(im), (void*)(PyArray_DATA(im)+offset), PyArray_ITEMSIZE(im), NPY_BEHAVED, NULL); block_iter = (PyArrayIterObject*)PyArray_IterNew((PyObject*)block); /* Compute block histogram */ histogram(H, clamp, block_iter); /* Free memory */ Py_XDECREF(block_iter); Py_XDECREF(block); return; }
//initialization of BallTree object // argument is a single array of size [D,N] static int BallTree_init(BallTreeObject *self, PyObject *args, PyObject *kwds){ //we use goto statements : all variables should be declared up front PyObject *arg=NULL; PyObject *arr=NULL; long int leaf_size=20; static char *kwlist[] = {"x", "leafsize", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|l", kwlist, &arg,&leaf_size) ) goto fail; if(leaf_size <= 0){ PyErr_SetString(PyExc_ValueError, "BallTree : leaf size must be greater than zero"); goto fail; } //view this object as an array of doubles, arr = PyArray_FROM_OTF(arg,NPY_DOUBLE,0); if(arr==NULL) goto fail; //check that it is 2D if( PyArray_NDIM(arr) != 2) goto fail; if(self != NULL){ //create the list of points self->size = PyArray_DIMS(arr)[0]; self->dim = PyArray_DIMS(arr)[1]; int inc = PyArray_STRIDES(arr)[1]/PyArray_DESCR(arr)->elsize; self->Points = new std::vector<BallTree_Point*>(self->size); for(int i=0;i<self->size;i++) self->Points->at(i) = new BallTree_Point(arr, (double*)PyArray_GETPTR2(arr,i,0), inc, PyArray_DIM(arr,1)); self->tree = new BallTree<BallTree_Point>(*(self->Points), leaf_size); } self->data = arr; //Py_DECREF(arr); return 0; fail: Py_XDECREF(arr); return -1; }
PyObject* rk(PyObject *self, PyObject *args) { double alpha; PyArrayObject* a; double beta; PyArrayObject* c; char trans = 'c'; if (!PyArg_ParseTuple(args, "dOdO|c", &alpha, &a, &beta, &c, &trans)) return NULL; int n = PyArray_DIMS(c)[0]; int k, lda; if (trans == 'c') { k = PyArray_DIMS(a)[1]; for (int d = 2; d < PyArray_NDIM(a); d++) k *= PyArray_DIMS(a)[d]; lda = k; } else { k = PyArray_DIMS(a)[0]; lda = n; } int ldc = PyArray_STRIDES(c)[0] / PyArray_STRIDES(c)[1]; if (PyArray_DESCR(a)->type_num == NPY_DOUBLE) dsyrk_("u", &trans, &n, &k, &alpha, DOUBLEP(a), &lda, &beta, DOUBLEP(c), &ldc); else zherk_("u", &trans, &n, &k, &alpha, (void*)COMPLEXP(a), &lda, &beta, (void*)COMPLEXP(c), &ldc); Py_RETURN_NONE; }
/* This also makes sure that the data segment is aligned with an itemsize address as well by returning one if not true. */ static int _bad_strides(PyArrayObject *ap) { register int itemsize = PyArray_ITEMSIZE(ap); register int i, N=PyArray_NDIM(ap); register intp *strides = PyArray_STRIDES(ap); if (((intp)(ap->data) % itemsize) != 0) return 1; for (i=0; i<N; i++) { if ((strides[i] < 0) || (strides[i] % itemsize) != 0) return 1; } return 0; }
/* Fill in the info structure */ static _buffer_info_t* _buffer_info_new(PyArrayObject *arr) { _buffer_info_t *info; _tmp_string_t fmt = {NULL, 0, 0}; int k; info = malloc(sizeof(_buffer_info_t)); if (info == NULL) { goto fail; } /* Fill in format */ if (_buffer_format_string(PyArray_DESCR(arr), &fmt, arr, NULL, NULL) != 0) { free(fmt.s); goto fail; } _append_char(&fmt, '\0'); info->format = fmt.s; /* Fill in shape and strides */ info->ndim = PyArray_NDIM(arr); if (info->ndim == 0) { info->shape = NULL; info->strides = NULL; } else { info->shape = malloc(sizeof(Py_ssize_t) * PyArray_NDIM(arr) * 2 + 1); if (info->shape == NULL) { goto fail; } info->strides = info->shape + PyArray_NDIM(arr); for (k = 0; k < PyArray_NDIM(arr); ++k) { info->shape[k] = PyArray_DIMS(arr)[k]; info->strides[k] = PyArray_STRIDES(arr)[k]; } } return info; fail: free(info); return NULL; }
/* Gets a half-open range [start, end) which contains the array data */ static void get_array_memory_extents(PyArrayObject *arr, npy_uintp *out_start, npy_uintp *out_end, npy_uintp *num_bytes) { npy_intp low, upper; int j; offset_bounds_from_strides(PyArray_ITEMSIZE(arr), PyArray_NDIM(arr), PyArray_DIMS(arr), PyArray_STRIDES(arr), &low, &upper); *out_start = (npy_uintp)PyArray_DATA(arr) + (npy_uintp)low; *out_end = (npy_uintp)PyArray_DATA(arr) + (npy_uintp)upper; *num_bytes = PyArray_ITEMSIZE(arr); for (j = 0; j < PyArray_NDIM(arr); ++j) { *num_bytes *= PyArray_DIM(arr, j); } }
static PyObject * array_repr_builtin(PyArrayObject *self, int repr) { PyObject *ret; char *string; /* max_n initial value is arbitrary, dump_data will extend it */ Py_ssize_t n = 0, max_n = PyArray_NBYTES(self) * 4 + 7; if ((string = PyArray_malloc(max_n)) == NULL) { return PyErr_NoMemory(); } if (dump_data(&string, &n, &max_n, PyArray_DATA(self), PyArray_NDIM(self), PyArray_DIMS(self), PyArray_STRIDES(self), self) < 0) { PyArray_free(string); return NULL; } if (repr) { if (PyArray_ISEXTENDED(self)) { ret = PyUString_FromFormat("array(%s, '%c%d')", string, PyArray_DESCR(self)->type, PyArray_DESCR(self)->elsize); } else { ret = PyUString_FromFormat("array(%s, '%c')", string, PyArray_DESCR(self)->type); } } else { ret = PyUString_FromStringAndSize(string, n); } PyArray_free(string); return ret; }
NPY_NO_EXPORT char * index2ptr(PyArrayObject *mp, npy_intp i) { npy_intp dim0; if (PyArray_NDIM(mp) == 0) { PyErr_SetString(PyExc_IndexError, "0-d arrays can't be indexed"); return NULL; } dim0 = PyArray_DIMS(mp)[0]; if (i < 0) { i += dim0; } if (i == 0 && dim0 > 0) { return PyArray_DATA(mp); } if (i > 0 && i < dim0) { return PyArray_DATA(mp)+i*PyArray_STRIDES(mp)[0]; } PyErr_SetString(PyExc_IndexError,"index out of bounds"); return NULL; }
/* * Allocates a result array for a reduction operation, with * dimensions matching 'arr' except set to 1 with 0 stride * wherever axis_flags is True. Dropping the reduction axes * from the result must be done later by the caller once the * computation is complete. * * This function always allocates a base class ndarray. * * If 'dtype' isn't NULL, this function steals its reference. */ static PyArrayObject * allocate_reduce_result(PyArrayObject *arr, npy_bool *axis_flags, PyArray_Descr *dtype, int subok) { npy_intp strides[NPY_MAXDIMS], stride; npy_intp shape[NPY_MAXDIMS], *arr_shape = PyArray_DIMS(arr); npy_stride_sort_item strideperm[NPY_MAXDIMS]; int idim, ndim = PyArray_NDIM(arr); if (dtype == NULL) { dtype = PyArray_DTYPE(arr); Py_INCREF(dtype); } PyArray_CreateSortedStridePerm(PyArray_NDIM(arr), PyArray_STRIDES(arr), strideperm); /* Build the new strides and shape */ stride = dtype->elsize; memcpy(shape, arr_shape, ndim * sizeof(shape[0])); for (idim = ndim-1; idim >= 0; --idim) { npy_intp i_perm = strideperm[idim].perm; if (axis_flags[i_perm]) { strides[i_perm] = 0; shape[i_perm] = 1; } else { strides[i_perm] = stride; stride *= shape[i_perm]; } } /* Finally, allocate the array */ return (PyArrayObject *)PyArray_NewFromDescr( subok ? Py_TYPE(arr) : &PyArray_Type, dtype, ndim, shape, strides, NULL, 0, subok ? (PyObject *)arr : NULL); }
static PyObject* try_to_return_parent(arystruct_t *arystruct, int ndim, PyArray_Descr *descr) { int i; PyArrayObject *array = (PyArrayObject *)arystruct->parent; if (!PyArray_Check(arystruct->parent)) /* Parent is a generic buffer-providing object */ goto RETURN_ARRAY_COPY; if (PyArray_DATA(array) != arystruct->data) goto RETURN_ARRAY_COPY; if (PyArray_NDIM(array) != ndim) goto RETURN_ARRAY_COPY; if (PyObject_RichCompareBool((PyObject *) PyArray_DESCR(array), (PyObject *) descr, Py_EQ) <= 0) goto RETURN_ARRAY_COPY; for(i = 0; i < ndim; ++i) { if (PyArray_DIMS(array)[i] != arystruct->shape_and_strides[i]) goto RETURN_ARRAY_COPY; if (PyArray_STRIDES(array)[i] != arystruct->shape_and_strides[ndim + i]) goto RETURN_ARRAY_COPY; } /* Yes, it is the same array Return new reference */ Py_INCREF((PyObject *)array); return (PyObject *)array; RETURN_ARRAY_COPY: return NULL; }
NPY_NO_EXPORT int _IsAligned(PyArrayObject *ap) { int i, alignment, aligned = 1; npy_intp ptr; /* The special casing for STRING and VOID types was removed * in accordance with http://projects.scipy.org/numpy/ticket/1227 * It used to be that IsAligned always returned True for these * types, which is indeed the case when they are created using * PyArray_DescrConverter(), but not necessarily when using * PyArray_DescrAlignConverter(). */ alignment = PyArray_DESCR(ap)->alignment; if (alignment == 1) { return 1; } ptr = (npy_intp) PyArray_DATA(ap); aligned = (ptr % alignment) == 0; for (i = 0; i < PyArray_NDIM(ap); i++) { aligned &= ((PyArray_STRIDES(ap)[i] % alignment) == 0); } return aligned != 0; }
/* * Conforms an output parameter 'out' to have 'ndim' dimensions * with dimensions of size one added in the appropriate places * indicated by 'axis_flags'. * * The return value is a view into 'out'. */ static PyArrayObject * conform_reduce_result(int ndim, npy_bool *axis_flags, PyArrayObject *out, int keepdims, const char *funcname, int need_copy) { npy_intp strides[NPY_MAXDIMS], shape[NPY_MAXDIMS]; npy_intp *strides_out = PyArray_STRIDES(out); npy_intp *shape_out = PyArray_DIMS(out); int idim, idim_out, ndim_out = PyArray_NDIM(out); PyArray_Descr *dtype; PyArrayObject_fields *ret; /* * If the 'keepdims' parameter is true, do a simpler validation and * return a new reference to 'out'. */ if (keepdims) { if (PyArray_NDIM(out) != ndim) { PyErr_Format(PyExc_ValueError, "output parameter for reduction operation %s " "has the wrong number of dimensions (must match " "the operand's when keepdims=True)", funcname); return NULL; } for (idim = 0; idim < ndim; ++idim) { if (axis_flags[idim]) { if (shape_out[idim] != 1) { PyErr_Format(PyExc_ValueError, "output parameter for reduction operation %s " "has a reduction dimension not equal to one " "(required when keepdims=True)", funcname); return NULL; } } } Py_INCREF(out); return out; } /* Construct the strides and shape */ idim_out = 0; for (idim = 0; idim < ndim; ++idim) { if (axis_flags[idim]) { strides[idim] = 0; shape[idim] = 1; } else { if (idim_out >= ndim_out) { PyErr_Format(PyExc_ValueError, "output parameter for reduction operation %s " "does not have enough dimensions", funcname); return NULL; } strides[idim] = strides_out[idim_out]; shape[idim] = shape_out[idim_out]; ++idim_out; } } if (idim_out != ndim_out) { PyErr_Format(PyExc_ValueError, "output parameter for reduction operation %s " "has too many dimensions", funcname); return NULL; } /* Allocate the view */ dtype = PyArray_DESCR(out); Py_INCREF(dtype); ret = (PyArrayObject_fields *)PyArray_NewFromDescr(&PyArray_Type, dtype, ndim, shape, strides, PyArray_DATA(out), PyArray_FLAGS(out), NULL); if (ret == NULL) { return NULL; } Py_INCREF(out); if (PyArray_SetBaseObject((PyArrayObject *)ret, (PyObject *)out) < 0) { Py_DECREF(ret); return NULL; } if (need_copy) { PyArrayObject *ret_copy; ret_copy = (PyArrayObject *)PyArray_NewLikeArray( (PyArrayObject *)ret, NPY_ANYORDER, NULL, 0); if (ret_copy == NULL) { Py_DECREF(ret); return NULL; } if (PyArray_CopyInto(ret_copy, (PyArrayObject *)ret) != 0) { Py_DECREF(ret); Py_DECREF(ret_copy); return NULL; } Py_INCREF(ret); if (PyArray_SetWritebackIfCopyBase(ret_copy, (PyArrayObject *)ret) < 0) { Py_DECREF(ret); Py_DECREF(ret_copy); return NULL; } return ret_copy; } else { return (PyArrayObject *)ret; } }
/* * Returns input array with values inserted sequentially into places * indicated by the mask */ NPY_NO_EXPORT PyObject * arr_insert(PyObject *NPY_UNUSED(self), PyObject *args, PyObject *kwdict) { PyObject *mask = NULL, *vals = NULL; PyArrayObject *ainput = NULL, *amask = NULL, *avals = NULL, *tmp = NULL; int numvals, totmask, sameshape; char *input_data, *mptr, *vptr, *zero = NULL; int melsize, delsize, nd, objarray, k; npy_intp *instrides, *inshape; static char *kwlist[] = {"input", "mask", "vals", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwdict, "O&OO", kwlist, PyArray_Converter, &ainput, &mask, &vals)) { goto fail; } amask = (PyArrayObject *)PyArray_FROM_OF(mask, NPY_ARRAY_CARRAY); if (amask == NULL) { goto fail; } /* Cast an object array */ if (PyArray_DESCR(amask)->type_num == NPY_OBJECT) { tmp = (PyArrayObject *)PyArray_Cast(amask, NPY_INTP); if (tmp == NULL) { goto fail; } Py_DECREF(amask); amask = tmp; } sameshape = 1; if (PyArray_NDIM(amask) == PyArray_NDIM(ainput)) { for (k = 0; k < PyArray_NDIM(amask); k++) { if (PyArray_DIMS(amask)[k] != PyArray_DIMS(ainput)[k]) { sameshape = 0; } } } else { /* Test to see if amask is 1d */ if (PyArray_NDIM(amask) != 1) { sameshape = 0; } else if ((PyArray_SIZE(ainput)) != PyArray_SIZE(amask)) { sameshape = 0; } } if (!sameshape) { PyErr_SetString(PyExc_TypeError, "mask array must be 1-d or same shape as input array"); goto fail; } avals = (PyArrayObject *)PyArray_FromObject(vals, PyArray_DESCR(ainput)->type_num, 0, 1); if (avals == NULL) { goto fail; } numvals = PyArray_SIZE(avals); nd = PyArray_NDIM(ainput); input_data = PyArray_DATA(ainput); mptr = PyArray_DATA(amask); melsize = PyArray_DESCR(amask)->elsize; vptr = PyArray_DATA(avals); delsize = PyArray_DESCR(avals)->elsize; zero = PyArray_Zero(amask); if (zero == NULL) { goto fail; } objarray = (PyArray_DESCR(ainput)->type_num == NPY_OBJECT); if (!numvals) { /* nothing to insert! fail unless none of mask is true */ const char *iter = mptr; const char *const last = iter + PyArray_NBYTES(amask); while (iter != last && !memcmp(iter, zero, melsize)) { iter += melsize; } if (iter != last) { PyErr_SetString(PyExc_ValueError, "Cannot insert from an empty array!"); goto fail; } goto finish; } /* Handle zero-dimensional case separately */ if (nd == 0) { if (memcmp(mptr,zero,melsize) != 0) { /* Copy value element over to input array */ memcpy(input_data,vptr,delsize); if (objarray) { Py_INCREF(*((PyObject **)vptr)); } } Py_DECREF(amask); Py_DECREF(avals); PyDataMem_FREE(zero); Py_DECREF(ainput); Py_RETURN_NONE; } totmask = (int) PyArray_SIZE(amask); instrides = PyArray_STRIDES(ainput); inshape = PyArray_DIMS(ainput); if (objarray) { /* object array, need to refcount, can't release the GIL */ arr_insert_loop(mptr, vptr, input_data, zero, PyArray_DATA(avals), melsize, delsize, objarray, totmask, numvals, nd, instrides, inshape); } else { /* No increfs take place in arr_insert_loop, so release the GIL */ NPY_BEGIN_ALLOW_THREADS; arr_insert_loop(mptr, vptr, input_data, zero, PyArray_DATA(avals), melsize, delsize, objarray, totmask, numvals, nd, instrides, inshape); NPY_END_ALLOW_THREADS; } finish: Py_DECREF(amask); Py_DECREF(avals); PyDataMem_FREE(zero); Py_DECREF(ainput); Py_RETURN_NONE; fail: PyDataMem_FREE(zero); Py_XDECREF(ainput); Py_XDECREF(amask); Py_XDECREF(avals); return NULL; }
/* * This function initializes a result array for a reduction operation * which has no identity. This means it needs to copy the first element * it sees along the reduction axes to result, then return a view of * the operand which excludes that element. * * If a reduction has an identity, such as 0 or 1, the result should be * initialized by calling PyArray_AssignZero(result, NULL, NULL) or * PyArray_AssignOne(result, NULL, NULL), because this function raises an * exception when there are no elements to reduce (which appropriate iff the * reduction operation has no identity). * * This means it copies the subarray indexed at zero along each reduction axis * into 'result', then returns a view into 'operand' excluding those copied * elements. * * result : The array into which the result is computed. This must have * the same number of dimensions as 'operand', but for each * axis i where 'axis_flags[i]' is True, it has a single element. * operand : The array being reduced. * axis_flags : An array of boolean flags, one for each axis of 'operand'. * When a flag is True, it indicates to reduce along that axis. * reorderable : If True, the reduction being done is reorderable, which * means specifying multiple axes of reduction at once is ok, * and the reduction code may calculate the reduction in an * arbitrary order. The calculation may be reordered because * of cache behavior or multithreading requirements. * out_skip_first_count : This gets populated with the number of first-visit * elements that should be skipped during the * iteration loop. * funcname : The name of the reduction operation, for the purpose of * better quality error messages. For example, "numpy.max" * would be a good name for NumPy's max function. * * Returns a view which contains the remaining elements on which to do * the reduction. */ NPY_NO_EXPORT PyArrayObject * PyArray_InitializeReduceResult( PyArrayObject *result, PyArrayObject *operand, npy_bool *axis_flags, int reorderable, npy_intp *out_skip_first_count, const char *funcname) { npy_intp *strides, *shape, shape_orig[NPY_MAXDIMS]; PyArrayObject *op_view = NULL; int idim, ndim, nreduce_axes; ndim = PyArray_NDIM(operand); /* Default to no skipping first-visit elements in the iteration */ *out_skip_first_count = 0; /* * If this reduction is non-reorderable, make sure there are * only 0 or 1 axes in axis_flags. */ if (!reorderable && check_nonreorderable_axes(ndim, axis_flags, funcname) < 0) { return NULL; } /* Take a view into 'operand' which we can modify. */ op_view = (PyArrayObject *)PyArray_View(operand, NULL, &PyArray_Type); if (op_view == NULL) { return NULL; } /* * Now copy the subarray of the first element along each reduction axis, * then return a view to the rest. * * Adjust the shape to only look at the first element along * any of the reduction axes. We count the number of reduction axes * at the same time. */ shape = PyArray_SHAPE(op_view); nreduce_axes = 0; memcpy(shape_orig, shape, ndim * sizeof(npy_intp)); for (idim = 0; idim < ndim; ++idim) { if (axis_flags[idim]) { if (shape[idim] == 0) { PyErr_Format(PyExc_ValueError, "zero-size array to reduction operation %s " "which has no identity", funcname); Py_DECREF(op_view); return NULL; } shape[idim] = 1; ++nreduce_axes; } } /* * Copy the elements into the result to start. */ if (PyArray_CopyInto(result, op_view) < 0) { Py_DECREF(op_view); return NULL; } /* * If there is one reduction axis, adjust the view's * shape to only look at the remaining elements */ if (nreduce_axes == 1) { strides = PyArray_STRIDES(op_view); for (idim = 0; idim < ndim; ++idim) { if (axis_flags[idim]) { shape[idim] = shape_orig[idim] - 1; ((PyArrayObject_fields *)op_view)->data += strides[idim]; } } } /* If there are zero reduction axes, make the view empty */ else if (nreduce_axes == 0) { for (idim = 0; idim < ndim; ++idim) { shape[idim] = 0; } } /* * Otherwise iterate over the whole operand, but tell the inner loop * to skip the elements we already copied by setting the skip_first_count. */ else { *out_skip_first_count = PyArray_SIZE(result); Py_DECREF(op_view); Py_INCREF(operand); op_view = operand; } return op_view; }
NPY_NO_EXPORT int PyArray_DTypeFromObjectHelper(PyObject *obj, int maxdims, PyArray_Descr **out_dtype, int string_type) { int i, size; PyArray_Descr *dtype = NULL; PyObject *ip; Py_buffer buffer_view; /* Check if it's an ndarray */ if (PyArray_Check(obj)) { dtype = PyArray_DESCR((PyArrayObject *)obj); Py_INCREF(dtype); goto promote_types; } /* See if it's a python None */ if (obj == Py_None) { dtype = PyArray_DescrFromType(NPY_OBJECT); if (dtype == NULL) { goto fail; } Py_INCREF(dtype); goto promote_types; } /* Check if it's a NumPy scalar */ else if (PyArray_IsScalar(obj, Generic)) { if (!string_type) { dtype = PyArray_DescrFromScalar(obj); if (dtype == NULL) { goto fail; } } else { int itemsize; PyObject *temp; if (string_type == NPY_STRING) { if ((temp = PyObject_Str(obj)) == NULL) { return -1; } #if defined(NPY_PY3K) #if PY_VERSION_HEX >= 0x03030000 itemsize = PyUnicode_GetLength(temp); #else itemsize = PyUnicode_GET_SIZE(temp); #endif #else itemsize = PyString_GET_SIZE(temp); #endif } else if (string_type == NPY_UNICODE) { #if defined(NPY_PY3K) if ((temp = PyObject_Str(obj)) == NULL) { #else if ((temp = PyObject_Unicode(obj)) == NULL) { #endif return -1; } itemsize = PyUnicode_GET_DATA_SIZE(temp); #ifndef Py_UNICODE_WIDE itemsize <<= 1; #endif } else { goto fail; } Py_DECREF(temp); if (*out_dtype != NULL && (*out_dtype)->type_num == string_type && (*out_dtype)->elsize >= itemsize) { return 0; } dtype = PyArray_DescrNewFromType(string_type); if (dtype == NULL) { goto fail; } dtype->elsize = itemsize; } goto promote_types; } /* Check if it's a Python scalar */ dtype = _array_find_python_scalar_type(obj); if (dtype != NULL) { if (string_type) { int itemsize; PyObject *temp; if (string_type == NPY_STRING) { if ((temp = PyObject_Str(obj)) == NULL) { return -1; } #if defined(NPY_PY3K) #if PY_VERSION_HEX >= 0x03030000 itemsize = PyUnicode_GetLength(temp); #else itemsize = PyUnicode_GET_SIZE(temp); #endif #else itemsize = PyString_GET_SIZE(temp); #endif } else if (string_type == NPY_UNICODE) { #if defined(NPY_PY3K) if ((temp = PyObject_Str(obj)) == NULL) { #else if ((temp = PyObject_Unicode(obj)) == NULL) { #endif return -1; } itemsize = PyUnicode_GET_DATA_SIZE(temp); #ifndef Py_UNICODE_WIDE itemsize <<= 1; #endif } else { goto fail; } Py_DECREF(temp); if (*out_dtype != NULL && (*out_dtype)->type_num == string_type && (*out_dtype)->elsize >= itemsize) { return 0; } dtype = PyArray_DescrNewFromType(string_type); if (dtype == NULL) { goto fail; } dtype->elsize = itemsize; } goto promote_types; } /* Check if it's an ASCII string */ if (PyBytes_Check(obj)) { int itemsize = PyString_GET_SIZE(obj); /* If it's already a big enough string, don't bother type promoting */ if (*out_dtype != NULL && (*out_dtype)->type_num == NPY_STRING && (*out_dtype)->elsize >= itemsize) { return 0; } dtype = PyArray_DescrNewFromType(NPY_STRING); if (dtype == NULL) { goto fail; } dtype->elsize = itemsize; goto promote_types; } /* Check if it's a Unicode string */ if (PyUnicode_Check(obj)) { int itemsize = PyUnicode_GET_DATA_SIZE(obj); #ifndef Py_UNICODE_WIDE itemsize <<= 1; #endif /* * If it's already a big enough unicode object, * don't bother type promoting */ if (*out_dtype != NULL && (*out_dtype)->type_num == NPY_UNICODE && (*out_dtype)->elsize >= itemsize) { return 0; } dtype = PyArray_DescrNewFromType(NPY_UNICODE); if (dtype == NULL) { goto fail; } dtype->elsize = itemsize; goto promote_types; } /* PEP 3118 buffer interface */ if (PyObject_CheckBuffer(obj) == 1) { memset(&buffer_view, 0, sizeof(Py_buffer)); if (PyObject_GetBuffer(obj, &buffer_view, PyBUF_FORMAT|PyBUF_STRIDES) == 0 || PyObject_GetBuffer(obj, &buffer_view, PyBUF_FORMAT) == 0) { PyErr_Clear(); dtype = _descriptor_from_pep3118_format(buffer_view.format); PyBuffer_Release(&buffer_view); if (dtype) { goto promote_types; } } else if (PyObject_GetBuffer(obj, &buffer_view, PyBUF_STRIDES) == 0 || PyObject_GetBuffer(obj, &buffer_view, PyBUF_SIMPLE) == 0) { PyErr_Clear(); dtype = PyArray_DescrNewFromType(NPY_VOID); dtype->elsize = buffer_view.itemsize; PyBuffer_Release(&buffer_view); goto promote_types; } else { PyErr_Clear(); } } /* The array interface */ ip = PyArray_GetAttrString_SuppressException(obj, "__array_interface__"); if (ip != NULL) { if (PyDict_Check(ip)) { PyObject *typestr; #if defined(NPY_PY3K) PyObject *tmp = NULL; #endif typestr = PyDict_GetItemString(ip, "typestr"); #if defined(NPY_PY3K) /* Allow unicode type strings */ if (PyUnicode_Check(typestr)) { tmp = PyUnicode_AsASCIIString(typestr); typestr = tmp; } #endif if (typestr && PyBytes_Check(typestr)) { dtype =_array_typedescr_fromstr(PyBytes_AS_STRING(typestr)); #if defined(NPY_PY3K) if (tmp == typestr) { Py_DECREF(tmp); } #endif Py_DECREF(ip); if (dtype == NULL) { goto fail; } goto promote_types; } } Py_DECREF(ip); } /* The array struct interface */ ip = PyArray_GetAttrString_SuppressException(obj, "__array_struct__"); if (ip != NULL) { PyArrayInterface *inter; char buf[40]; if (NpyCapsule_Check(ip)) { inter = (PyArrayInterface *)NpyCapsule_AsVoidPtr(ip); if (inter->two == 2) { PyOS_snprintf(buf, sizeof(buf), "|%c%d", inter->typekind, inter->itemsize); dtype = _array_typedescr_fromstr(buf); Py_DECREF(ip); if (dtype == NULL) { goto fail; } goto promote_types; } } Py_DECREF(ip); } /* The old buffer interface */ #if !defined(NPY_PY3K) if (PyBuffer_Check(obj)) { dtype = PyArray_DescrNewFromType(NPY_VOID); if (dtype == NULL) { goto fail; } dtype->elsize = Py_TYPE(obj)->tp_as_sequence->sq_length(obj); PyErr_Clear(); goto promote_types; } #endif /* The __array__ attribute */ ip = PyArray_GetAttrString_SuppressException(obj, "__array__"); if (ip != NULL) { Py_DECREF(ip); ip = PyObject_CallMethod(obj, "__array__", NULL); if(ip && PyArray_Check(ip)) { dtype = PyArray_DESCR((PyArrayObject *)ip); Py_INCREF(dtype); Py_DECREF(ip); goto promote_types; } Py_XDECREF(ip); if (PyErr_Occurred()) { goto fail; } } /* Not exactly sure what this is about... */ #if !defined(NPY_PY3K) if (PyInstance_Check(obj)) { dtype = _use_default_type(obj); if (dtype == NULL) { goto fail; } else { goto promote_types; } } #endif /* * If we reached the maximum recursion depth without hitting one * of the above cases, the output dtype should be OBJECT */ if (maxdims == 0 || !PySequence_Check(obj)) { if (*out_dtype == NULL || (*out_dtype)->type_num != NPY_OBJECT) { Py_XDECREF(*out_dtype); *out_dtype = PyArray_DescrFromType(NPY_OBJECT); if (*out_dtype == NULL) { return -1; } } return 0; } /* Recursive case */ size = PySequence_Size(obj); if (size < 0) { goto fail; } /* Recursive call for each sequence item */ for (i = 0; i < size; ++i) { int res; ip = PySequence_GetItem(obj, i); if (ip == NULL) { goto fail; } res = PyArray_DTypeFromObjectHelper(ip, maxdims - 1, out_dtype, string_type); if (res < 0) { Py_DECREF(ip); goto fail; } else if (res > 0) { Py_DECREF(ip); return res; } Py_DECREF(ip); } return 0; promote_types: /* Set 'out_dtype' if it's NULL */ if (*out_dtype == NULL) { if (!string_type && dtype->type_num == NPY_STRING) { Py_DECREF(dtype); return RETRY_WITH_STRING; } if (!string_type && dtype->type_num == NPY_UNICODE) { Py_DECREF(dtype); return RETRY_WITH_UNICODE; } *out_dtype = dtype; return 0; } /* Do type promotion with 'out_dtype' */ else { PyArray_Descr *res_dtype = PyArray_PromoteTypes(dtype, *out_dtype); Py_DECREF(dtype); if (res_dtype == NULL) { return -1; } if (!string_type && res_dtype->type_num == NPY_UNICODE && (*out_dtype)->type_num != NPY_UNICODE) { Py_DECREF(res_dtype); return RETRY_WITH_UNICODE; } if (!string_type && res_dtype->type_num == NPY_STRING && (*out_dtype)->type_num != NPY_STRING) { Py_DECREF(res_dtype); return RETRY_WITH_STRING; } Py_DECREF(*out_dtype); *out_dtype = res_dtype; return 0; } fail: Py_XDECREF(*out_dtype); *out_dtype = NULL; return -1; } #undef RETRY_WITH_STRING #undef RETRY_WITH_UNICODE /* new reference */ NPY_NO_EXPORT PyArray_Descr * _array_typedescr_fromstr(char *c_str) { PyArray_Descr *descr = NULL; PyObject *stringobj = PyString_FromString(c_str); if (stringobj == NULL) { return NULL; } if (PyArray_DescrConverter(stringobj, &descr) != NPY_SUCCEED) { Py_DECREF(stringobj); return NULL; } Py_DECREF(stringobj); return descr; } NPY_NO_EXPORT char * index2ptr(PyArrayObject *mp, npy_intp i) { npy_intp dim0; if (PyArray_NDIM(mp) == 0) { PyErr_SetString(PyExc_IndexError, "0-d arrays can't be indexed"); return NULL; } dim0 = PyArray_DIMS(mp)[0]; if (check_and_adjust_index(&i, dim0, 0) < 0) return NULL; if (i == 0) { return PyArray_DATA(mp); } return PyArray_BYTES(mp)+i*PyArray_STRIDES(mp)[0]; }
static size_t wrap_send(uhd::tx_streamer *tx_stream, bp::object &np_array, bp::object &metadata, const double timeout = 0.1) { // Extract the metadata bp::extract<uhd::tx_metadata_t&> get_metadata(metadata); // TODO: throw an error here? if (not get_metadata.check()) { return 0; } // Get a numpy array object from given python object // No sanity checking possible! // Note: this increases the ref count, which we'll need to manually decrease at the end PyObject* array_obj = PyArray_FROM_OF(np_array.ptr(),NPY_ARRAY_CARRAY); PyArrayObject* array_type_obj = reinterpret_cast<PyArrayObject*>(array_obj); // Get dimensions of the numpy array const size_t dims = PyArray_NDIM(array_type_obj); const npy_intp* shape = PyArray_SHAPE(array_type_obj); // How many bytes to jump to get to the next element of the stride // (next row) const npy_intp* strides = PyArray_STRIDES(array_type_obj); const size_t channels = tx_stream->get_num_channels(); // Check if numpy array sizes are ok if (((channels > 1) && (dims != 2)) or ((size_t) shape[0] < channels)) { // Manually decrement the ref count Py_DECREF(array_obj); // If we don't have a 2D NumPy array, assume we have a 1D array size_t input_channels = (dims != 2) ? 1 : shape[0]; throw uhd::runtime_error(str(boost::format( "Number of TX channels (%d) does not match the dimensions of the data array (%d)") % channels % input_channels)); } // Get a pointer to the storage std::vector<void*> channel_storage; char* data = PyArray_BYTES(array_type_obj); for (size_t i = 0; i < channels; ++i) { channel_storage.push_back((void*)(data + i * strides[0])); } // Get data buffer and size of the array size_t nsamps_per_buff = (dims > 1) ? (size_t) shape[1] : PyArray_SIZE(array_type_obj); // Release the GIL only for the send() call const size_t result = [&]() { scoped_gil_release gil_release; // Call the real send() return tx_stream->send( channel_storage, nsamps_per_buff, get_metadata(), timeout ); }(); // Manually decrement the ref count Py_DECREF(array_obj); return result; }
/* Fill in the info structure */ static _buffer_info_t* _buffer_info_new(PyObject *obj) { _buffer_info_t *info; _tmp_string_t fmt = {NULL, 0, 0}; int k; PyArray_Descr *descr = NULL; int err = 0; info = malloc(sizeof(_buffer_info_t)); if (info == NULL) { PyErr_NoMemory(); goto fail; } if (PyArray_IsScalar(obj, Datetime) || PyArray_IsScalar(obj, Timedelta)) { /* * Special case datetime64 scalars to remain backward compatible. * This will change in a future version. * Note arrays of datetime64 and strutured arrays with datetime64 * fields will not hit this code path and are currently unsupported * in _buffer_format_string. */ if (_append_char(&fmt, 'B') < 0) { goto fail; } if (_append_char(&fmt, '\0') < 0) { goto fail; } info->ndim = 1; info->shape = malloc(sizeof(Py_ssize_t) * 2); if (info->shape == NULL) { PyErr_NoMemory(); goto fail; } info->strides = info->shape + info->ndim; info->shape[0] = 8; info->strides[0] = 1; info->format = fmt.s; return info; } else if (PyArray_IsScalar(obj, Generic)) { descr = PyArray_DescrFromScalar(obj); if (descr == NULL) { goto fail; } info->ndim = 0; info->shape = NULL; info->strides = NULL; } else { PyArrayObject * arr = (PyArrayObject *)obj; descr = PyArray_DESCR(arr); /* Fill in shape and strides */ info->ndim = PyArray_NDIM(arr); if (info->ndim == 0) { info->shape = NULL; info->strides = NULL; } else { info->shape = malloc(sizeof(Py_ssize_t) * PyArray_NDIM(arr) * 2 + 1); if (info->shape == NULL) { PyErr_NoMemory(); goto fail; } info->strides = info->shape + PyArray_NDIM(arr); for (k = 0; k < PyArray_NDIM(arr); ++k) { info->shape[k] = PyArray_DIMS(arr)[k]; info->strides[k] = PyArray_STRIDES(arr)[k]; } } Py_INCREF(descr); } /* Fill in format */ err = _buffer_format_string(descr, &fmt, obj, NULL, NULL); Py_DECREF(descr); if (err != 0) { goto fail; } if (_append_char(&fmt, '\0') < 0) { goto fail; } info->format = fmt.s; return info; fail: free(fmt.s); free(info); return NULL; }