diff options
-rw-r--r-- | numpy/core/src/multiarray/lowlevel_strided_loops.c.src | 349 |
1 files changed, 209 insertions, 140 deletions
diff --git a/numpy/core/src/multiarray/lowlevel_strided_loops.c.src b/numpy/core/src/multiarray/lowlevel_strided_loops.c.src index 2601acf36..153549b85 100644 --- a/numpy/core/src/multiarray/lowlevel_strided_loops.c.src +++ b/numpy/core/src/multiarray/lowlevel_strided_loops.c.src @@ -790,55 +790,6 @@ PyArray_GetStridedZeroPadCopyFn(npy_intp aligned, } } -/*************************** DTYPE CAST FUNCTIONS *************************/ - -/* Does a simple aligned cast */ -typedef struct { - void *freefunc, *copyfunc; - PyArray_VectorUnaryFunc *castfunc; -} _strided_cast_data; - -/* strided cast data copy function */ -_strided_cast_data *_strided_cast_data_copy(_strided_cast_data *data) -{ - _strided_cast_data *newdata = - (_strided_cast_data *)PyArray_malloc(sizeof(_strided_cast_data)); - if (newdata == NULL) { - return NULL; - } - - memcpy(newdata, data, sizeof(_strided_cast_data)); - - return newdata; -} - -static void -_aligned_strided_to_strided_cast(char *dst, npy_intp dst_stride, - char *src, npy_intp src_stride, - npy_intp N, npy_intp src_itemsize, - void *data) -{ - PyArray_VectorUnaryFunc *castfunc = ((_strided_cast_data *)data)->castfunc; - - while (N > 0) { - castfunc(src, dst, 1, NULL, NULL); - dst += dst_stride; - src += src_stride; - --N; - } -} - -static void -_aligned_contig_to_contig_cast(char *dst, npy_intp NPY_UNUSED(dst_stride), - char *src, npy_intp NPY_UNUSED(src_stride), - npy_intp N, npy_intp NPY_UNUSED(itemsize), - void *data) -{ - PyArray_VectorUnaryFunc *castfunc = ((_strided_cast_data *)data)->castfunc; - - castfunc(src, dst, N, NULL, NULL); -} - /***************** WRAP ALIGNED CONTIGUOUS TRANFSER FUNCTION **************/ /* Wraps a transfer function + data in alignment code */ @@ -938,8 +889,10 @@ _strided_to_strided_contig_align_wrap(char *dst, npy_intp dst_stride, * data passed to 'frombuffer' is NULL. * wrapped - contig to contig transfer function being wrapped * wrappeddata - data for wrapped + * + * Returns NPY_SUCCEED or NPY_FAIL. */ -NPY_NO_EXPORT void +NPY_NO_EXPORT int PyArray_WrapAlignedContigTransferFunction( npy_intp src_itemsize, npy_intp dst_itemsize, PyArray_StridedTransferFn tobuffer, @@ -958,6 +911,10 @@ PyArray_WrapAlignedContigTransferFunction( /* Allocate the data, and populate it */ data = (_align_wrap_data *)PyArray_malloc(datasize); + if (data == NULL) { + PyErr_NoMemory(); + return NPY_FAIL; + } data->freefunc = (void *)&_align_wrap_data_free; data->copyfunc = (void *)&_align_wrap_data_copy; data->tobuffer = tobuffer; @@ -972,6 +929,199 @@ PyArray_WrapAlignedContigTransferFunction( /* Set the function and data */ *outstransfer = &_strided_to_strided_contig_align_wrap; *outtransferdata = data; + + return NPY_SUCCEED; +} + +/*************************** DTYPE CAST FUNCTIONS *************************/ + +/* Does a simple aligned cast */ +typedef struct { + void *freefunc, *copyfunc; + PyArray_VectorUnaryFunc *castfunc; + PyArrayObject *aip, *aop; +} _strided_cast_data; + +/* strided cast data free function */ +void _strided_cast_data_free(_strided_cast_data *data) +{ + Py_DECREF(data->aip); + Py_DECREF(data->aop); + PyArray_free(data); +} + +/* strided cast data copy function */ +_strided_cast_data *_strided_cast_data_copy(_strided_cast_data *data) +{ + _strided_cast_data *newdata = + (_strided_cast_data *)PyArray_malloc(sizeof(_strided_cast_data)); + if (newdata == NULL) { + return NULL; + } + + memcpy(newdata, data, sizeof(_strided_cast_data)); + Py_INCREF(newdata->aip); + Py_INCREF(newdata->aop); + + return newdata; +} + +static void +_aligned_strided_to_strided_cast(char *dst, npy_intp dst_stride, + char *src, npy_intp src_stride, + npy_intp N, npy_intp src_itemsize, + void *data) +{ + _strided_cast_data *d = (_strided_cast_data *)data; + PyArray_VectorUnaryFunc *castfunc = d->castfunc; + PyArrayObject *aip = d->aip, *aop = d->aop; + + while (N > 0) { + castfunc(src, dst, 1, aip, aop); + dst += dst_stride; + src += src_stride; + --N; + } +} + +static void +_aligned_contig_to_contig_cast(char *dst, npy_intp NPY_UNUSED(dst_stride), + char *src, npy_intp NPY_UNUSED(src_stride), + npy_intp N, npy_intp NPY_UNUSED(itemsize), + void *data) +{ + _strided_cast_data *d = (_strided_cast_data *)data; + PyArray_VectorUnaryFunc *castfunc = d->castfunc; + PyArrayObject *aip = d->aip, *aop = d->aop; + + castfunc(src, dst, N, aip, aop); +} + +static int +get_cast_transfer_function(int aligned, + npy_intp src_stride, npy_intp dst_stride, + PyArray_Descr *src_dtype, PyArray_Descr *dst_dtype, + int move_references, + PyArray_StridedTransferFn *outstransfer, + void **outtransferdata) +{ + _strided_cast_data *data; + PyArray_VectorUnaryFunc *castfunc; + npy_intp shape = 1, src_itemsize = src_dtype->elsize, + dst_itemsize = dst_dtype->elsize; + + /* Get the cast function */ + castfunc = PyArray_GetCastFunc(src_dtype, dst_dtype->type_num); + if (!castfunc) { + *outstransfer = NULL; + *outtransferdata = NULL; + return NPY_FAIL; + } + + /* Allocate the data for the casting */ + data = (_strided_cast_data *)PyArray_malloc(sizeof(_strided_cast_data)); + if (data == NULL) { + PyErr_NoMemory(); + *outstransfer = NULL; + *outtransferdata = NULL; + return NPY_FAIL; + } + data->freefunc = (void*)&_strided_cast_data_free; + data->copyfunc = (void*)&_strided_cast_data_copy; + data->castfunc = castfunc; + Py_INCREF(src_dtype); + data->aip = (PyArrayObject *)PyArray_NewFromDescr(&PyArray_Type, src_dtype, + 1, &shape, NULL, NULL, 0, NULL); + if (data->aip == NULL) { + PyArray_free(data); + return NPY_FAIL; + } + Py_INCREF(dst_dtype); + data->aop = (PyArrayObject *)PyArray_NewFromDescr(&PyArray_Type, dst_dtype, + 1, &shape, NULL, NULL, 0, NULL); + if (data->aop == NULL) { + Py_DECREF(data->aip); + PyArray_free(data); + return NPY_FAIL; + } + + + /* If it's aligned and all native byte order, we're all done */ + if (aligned && PyArray_ISNBO(src_dtype->byteorder) && + PyArray_ISNBO(dst_dtype->byteorder)) { + /* Choose the contiguous cast if we can */ + if (src_stride == src_itemsize && dst_stride == dst_itemsize) { + *outstransfer = _aligned_contig_to_contig_cast; + } + else { + *outstransfer = _aligned_strided_to_strided_cast; + } + *outtransferdata = data; + + return NPY_SUCCEED; + } + /* Otherwise, we have to copy and/or swap to aligned temporaries */ + else { + PyArray_StridedTransferFn tobuffer, frombuffer, casttransfer; + + /* Get the copy/swap operation from src */ + if (src_itemsize == 1 || PyArray_ISNBO(src_dtype->byteorder)) { + tobuffer = PyArray_GetStridedCopyFn(aligned, + src_stride, src_itemsize, + src_itemsize); + } + /* If it's not complex, one swap */ + else if(src_dtype->kind != 'c') { + tobuffer = PyArray_GetStridedCopySwapFn(aligned, + src_stride, src_itemsize, + src_itemsize); + } + /* If not complex, a paired swap */ + else { + tobuffer = PyArray_GetStridedCopySwapPairFn(aligned, + src_stride, src_itemsize, + src_itemsize); + } + + /* Get the copy/swap operation to dst */ + if (dst_itemsize == 1 || PyArray_ISNBO(dst_dtype->byteorder)) { + frombuffer = PyArray_GetStridedCopyFn(aligned, + dst_itemsize, dst_stride, + dst_itemsize); + } + /* If it's not complex, one swap */ + else if(dst_dtype->kind != 'c') { + frombuffer = PyArray_GetStridedCopySwapFn(aligned, + dst_itemsize, dst_stride, + dst_itemsize); + } + /* If not complex, a paired swap */ + else { + frombuffer = PyArray_GetStridedCopySwapPairFn(aligned, + dst_itemsize, dst_stride, + dst_itemsize); + } + + if (frombuffer == NULL || tobuffer == NULL) { + PyArray_FreeStridedTransferData(data); + return NPY_FAIL; + } + + /* Use the aligned contiguous cast */ + casttransfer = &_aligned_contig_to_contig_cast; + + /* Wrap it all up in a new transfer function + data */ + if (PyArray_WrapAlignedContigTransferFunction( + src_itemsize, dst_itemsize, + tobuffer, frombuffer, + casttransfer, data, + outstransfer, outtransferdata) != NPY_SUCCEED) { + PyArray_FreeStridedTransferData(data); + return NPY_FAIL; + } + + return NPY_SUCCEED; + } } /**************************** COPY 1 TO N CONTIGUOUS ************************/ @@ -1643,6 +1793,8 @@ PyArray_GetDTypeTransferFunction(int aligned, outstransfer, outtransferdata); } + /* TODO: Handle fields here */ + /* Check for different-sized strings or unicode */ if (src_type_num == dst_type_num) switch (src_type_num) { case NPY_STRING: @@ -1655,101 +1807,18 @@ PyArray_GetDTypeTransferFunction(int aligned, } /* Check whether a simple cast and some swaps will suffice */ - if (src_type_num < NPY_OBJECT && dst_type_num < NPY_OBJECT) { - _strided_cast_data *data; - PyArray_VectorUnaryFunc *castfunc; - - /* Get the cast function */ - castfunc = PyArray_GetCastFunc(src_dtype, dst_type_num); - if (!castfunc) { - *outstransfer = NULL; - *outtransferdata = NULL; - return NPY_FAIL; - } - - /* Allocate the data for the casting */ - data = (_strided_cast_data *)PyArray_malloc(sizeof(_strided_cast_data)); - if (data == NULL) { - PyErr_NoMemory(); - *outstransfer = NULL; - *outtransferdata = NULL; - return NPY_FAIL; - } - data->freefunc = (void*)&(PyArray_free); - data->copyfunc = (void*)&(_strided_cast_data_copy); - data->castfunc = castfunc; - - - /* If it's aligned and all native byte order, we're all done */ - if (aligned && PyArray_ISNBO(src_dtype->byteorder) && - PyArray_ISNBO(dst_dtype->byteorder)) { - /* Choose the contiguous cast if we can */ - if (src_stride == src_itemsize && dst_stride == dst_itemsize) { - *outstransfer = _aligned_contig_to_contig_cast; - } - else { - *outstransfer = _aligned_strided_to_strided_cast; - } - *outtransferdata = data; - - return NPY_SUCCEED; - } - /* Otherwise, we have to copy and/or swap to aligned temporaries */ - else { - PyArray_StridedTransferFn tobuffer, frombuffer, casttransfer; - - /* Get the copy/swap operation from src */ - if (src_itemsize == 1 || PyArray_ISNBO(src_dtype->byteorder)) { - tobuffer = PyArray_GetStridedCopyFn(aligned, - src_stride, src_itemsize, - src_itemsize); - } - else if(!PyTypeNum_ISCOMPLEX(src_type_num)) { - tobuffer = PyArray_GetStridedCopySwapFn(aligned, - src_stride, src_itemsize, - src_itemsize); - } - else { - tobuffer = PyArray_GetStridedCopySwapPairFn(aligned, - src_stride, src_itemsize, - src_itemsize); - } - - /* Get the copy/swap operation to dst */ - if (dst_itemsize == 1 || PyArray_ISNBO(dst_dtype->byteorder)) { - frombuffer = PyArray_GetStridedCopyFn(aligned, - dst_itemsize, dst_stride, - dst_itemsize); - } - else if(!PyTypeNum_ISCOMPLEX(dst_type_num)) { - frombuffer = PyArray_GetStridedCopySwapFn(aligned, - dst_itemsize, dst_stride, - dst_itemsize); - } - else { - frombuffer = PyArray_GetStridedCopySwapPairFn(aligned, - dst_itemsize, dst_stride, - dst_itemsize); - } - - /* Use the aligned contiguous cast */ - casttransfer = &_aligned_contig_to_contig_cast; - - /* Wrap it all up in a new transfer function + data */ - PyArray_WrapAlignedContigTransferFunction( - src_itemsize, dst_itemsize, - tobuffer, frombuffer, - casttransfer, data, - outstransfer, outtransferdata); - - return NPY_SUCCEED; - } + if (src_type_num < NPY_NTYPES && dst_type_num < NPY_NTYPES) { + return get_cast_transfer_function(aligned, + src_stride, dst_stride, + src_dtype, dst_dtype, + move_references, + outstransfer, outtransferdata); } /* TODO check for fields & subarrays */ printf("\n"); PyObject_Print((PyObject *)src_dtype, stdout, 0); - printf(" "); + printf(" -> "); PyObject_Print((PyObject *)dst_dtype, stdout, 0); printf("\n"); |