numpy 2.0.0
src/private/lowlevel_strided_loops.h File Reference

Go to the source code of this file.

Defines

#define PyArray_EQUIVALENTLY_ITERABLE(arr1, arr2)
#define PyArray_TRIVIALLY_ITERABLE(arr)
#define PyArray_PREPARE_TRIVIAL_ITERATION(arr, count, data, stride)
#define PyArray_TRIVIALLY_ITERABLE_PAIR(arr1, arr2)
#define PyArray_PREPARE_TRIVIAL_PAIR_ITERATION(arr1, arr2, count, data1, data2, stride1, stride2)
#define PyArray_TRIVIALLY_ITERABLE_TRIPLE(arr1, arr2, arr3)
#define PyArray_PREPARE_TRIVIAL_TRIPLE_ITERATION(arr1, arr2, arr3, count, data1, data2, data3, stride1, stride2, stride3)

Typedefs

typedef void( PyArray_StridedTransferFn )(char *dst, npy_intp dst_stride, char *src, npy_intp src_stride, npy_intp N, npy_intp src_itemsize, void *transferdata)

Functions

NPY_NO_EXPORT void PyArray_FreeStridedTransferData (void *transferdata)
NPY_NO_EXPORT void * PyArray_CopyStridedTransferData (void *transferdata)
NPY_NO_EXPORT
PyArray_StridedTransferFn
PyArray_GetStridedCopyFn (npy_intp aligned, npy_intp src_stride, npy_intp dst_stride, npy_intp itemsize)
NPY_NO_EXPORT
PyArray_StridedTransferFn
PyArray_GetStridedCopySwapFn (npy_intp aligned, npy_intp src_stride, npy_intp dst_stride, npy_intp itemsize)
NPY_NO_EXPORT
PyArray_StridedTransferFn
PyArray_GetStridedCopySwapPairFn (npy_intp aligned, npy_intp src_stride, npy_intp dst_stride, npy_intp itemsize)
NPY_NO_EXPORT int PyArray_GetStridedZeroPadCopyFn (int aligned, npy_intp src_stride, npy_intp dst_stride, npy_intp src_itemsize, npy_intp dst_itemsize, PyArray_StridedTransferFn **outstransfer, void **outtransferdata)
NPY_NO_EXPORT
PyArray_StridedTransferFn
PyArray_GetStridedNumericCastFn (npy_intp aligned, npy_intp src_stride, npy_intp dst_stride, int src_type_num, int dst_type_num)
NPY_NO_EXPORT int PyArray_GetDTypeTransferFunction (int aligned, npy_intp src_stride, npy_intp dst_stride, PyArray_Descr *src_dtype, PyArray_Descr *dst_dtype, int move_references, PyArray_StridedTransferFn **out_stransfer, void **out_transferdata, int *out_needs_api)
NPY_NO_EXPORT npy_intp PyArray_TransferNDimToStrided (npy_intp ndim, char *dst, npy_intp dst_stride, char *src, npy_intp *src_strides, npy_intp src_strides_inc, npy_intp *coords, npy_intp coords_inc, npy_intp *shape, npy_intp shape_inc, npy_intp count, npy_intp src_itemsize, PyArray_StridedTransferFn *stransfer, void *transferdata)
NPY_NO_EXPORT npy_intp PyArray_TransferStridedToNDim (npy_intp ndim, char *dst, npy_intp *dst_strides, npy_intp dst_strides_inc, char *src, npy_intp src_stride, npy_intp *coords, npy_intp coords_inc, npy_intp *shape, npy_intp shape_inc, npy_intp count, npy_intp src_itemsize, PyArray_StridedTransferFn *stransfer, void *transferdata)

Define Documentation

#define PyArray_EQUIVALENTLY_ITERABLE (   arr1,
  arr2 
)
Value:
( \
                        PyArray_NDIM(arr1) == PyArray_NDIM(arr2) && \
                        PyArray_CompareLists(PyArray_DIMS(arr1), \
                                             PyArray_DIMS(arr2), \
                                             PyArray_NDIM(arr1)) && \
                        (arr1->flags&(NPY_CONTIGUOUS|NPY_FORTRAN)) == \
                                (arr2->flags&(NPY_CONTIGUOUS|NPY_FORTRAN)) \
                        )
<blockquote> TRIVIAL ITERATION</blockquote>
In some cases when the iteration order isn't important, iteration over arrays is trivial. This is the case when:

System Message: ERROR/3 (<string>, line 5) Unexpected indentation.

<blockquote>

  • The array has 0 or 1 dimensions.
  • The array is C or Fortran contiguous.

</blockquote>

System Message: WARNING/2 (<string>, line 7) Block quote ends without a blank line; unexpected unindent.
Use of an iterator can be skipped when this occurs. These macros assist in detecting and taking advantage of the situation. Note that it may be worthwhile to further check if the stride is a contiguous stride and take advantage of that.
Here is example code for a single array: <blockquote>

if (PyArray_TRIVIALLY_ITERABLE(self) {

char *data; npy_intp count, stride;

System Message: WARNING/2 (<string>, line 15); backlink Inline emphasis start-string without end-string.

PyArray_PREPARE_TRIVIAL_ITERATION(self, count, data, stride);

while (count--) {

// Use the data pointer

data += stride;

System Message: WARNING/2 (<string>, line 24) Definition list ends without a blank line; unexpected unindent.

}

System Message: WARNING/2 (<string>, line 25) Definition list ends without a blank line; unexpected unindent.
} else {

System Message: ERROR/3 (<string>, line 27) Unexpected indentation.

<blockquote> Create iterator, etc...</blockquote>

System Message: WARNING/2 (<string>, line 28) Block quote ends without a blank line; unexpected unindent.
} </blockquote>
Here is example code for a pair of arrays: <blockquote>

if (PyArray_TRIVIALLY_ITERABLE_PAIR(a1, a2) {

char *data1, *data2; npy_intp count, stride1, stride2;

System Message: WARNING/2 (<string>, line 33); backlink Inline emphasis start-string without end-string.
System Message: WARNING/2 (<string>, line 33); backlink Inline emphasis start-string without end-string.
PyArray_PREPARE_TRIVIAL_PAIR_ITERATION(a1, a2, count,
data1, data2, stride1, stride2);
while (count--) {

// Use the data1 and data2 pointers

data1 += stride1; data2 += stride2;

System Message: WARNING/2 (<string>, line 44) Definition list ends without a blank line; unexpected unindent.

}

System Message: WARNING/2 (<string>, line 45) Definition list ends without a blank line; unexpected unindent.
} else {

System Message: ERROR/3 (<string>, line 47) Unexpected indentation.

<blockquote> Create iterator, etc...</blockquote>

System Message: WARNING/2 (<string>, line 48) Block quote ends without a blank line; unexpected unindent.
} </blockquote>
Note: Equivalently iterable macro requires one of arr1 or arr2 be
trivially iterable to be valid.
#define PyArray_PREPARE_TRIVIAL_ITERATION (   arr,
  count,
  data,
  stride 
)
Value:
count = PyArray_SIZE(arr), \
                    data = PyArray_BYTES(arr), \
                    stride = ((PyArray_NDIM(arr) == 0) ? 0 : \
                                (PyArray_CHKFLAGS(arr, NPY_FORTRAN) ? \
                                            PyArray_STRIDE(arr, 0) : \
                                            PyArray_STRIDE(arr, \
                                                PyArray_NDIM(arr)-1)))
#define PyArray_PREPARE_TRIVIAL_PAIR_ITERATION (   arr1,
  arr2,
  count,
  data1,
  data2,
  stride1,
  stride2 
)
Value:
{ \
                    npy_intp size1 = PyArray_SIZE(arr1); \
                    npy_intp size2 = PyArray_SIZE(arr2); \
                    count = ((size1 > size2) || size1 == 0) ? size1 : size2; \
                    data1 = PyArray_BYTES(arr1); \
                    data2 = PyArray_BYTES(arr2); \
                    stride1 = (size1 == 1 ? 0 : \
                                (PyArray_CHKFLAGS(arr1, NPY_FORTRAN) ? \
                                            PyArray_STRIDE(arr1, 0) : \
                                            PyArray_STRIDE(arr1, \
                                                PyArray_NDIM(arr1)-1))); \
                    stride2 = (size2 == 1 ? 0 : \
                                (PyArray_CHKFLAGS(arr2, NPY_FORTRAN) ? \
                                            PyArray_STRIDE(arr2, 0) : \
                                            PyArray_STRIDE(arr2, \
                                                PyArray_NDIM(arr2)-1))); \
                }
#define PyArray_PREPARE_TRIVIAL_TRIPLE_ITERATION (   arr1,
  arr2,
  arr3,
  count,
  data1,
  data2,
  data3,
  stride1,
  stride2,
  stride3 
)
Value:
{ \
                    npy_intp size1 = PyArray_SIZE(arr1); \
                    npy_intp size2 = PyArray_SIZE(arr2); \
                    npy_intp size3 = PyArray_SIZE(arr3); \
                    count = ((size1 > size2) || size1 == 0) ? size1 : size2; \
                    count = ((size3 > count) || size3 == 0) ? size3 : count; \
                    data1 = PyArray_BYTES(arr1); \
                    data2 = PyArray_BYTES(arr2); \
                    data3 = PyArray_BYTES(arr3); \
                    stride1 = (size1 == 1 ? 0 : \
                                (PyArray_CHKFLAGS(arr1, NPY_FORTRAN) ? \
                                            PyArray_STRIDE(arr1, 0) : \
                                            PyArray_STRIDE(arr1, \
                                                PyArray_NDIM(arr1)-1))); \
                    stride2 = (size2 == 1 ? 0 : \
                                (PyArray_CHKFLAGS(arr2, NPY_FORTRAN) ? \
                                            PyArray_STRIDE(arr2, 0) : \
                                            PyArray_STRIDE(arr2, \
                                                PyArray_NDIM(arr2)-1))); \
                    stride3 = (size3 == 1 ? 0 : \
                                (PyArray_CHKFLAGS(arr3, NPY_FORTRAN) ? \
                                            PyArray_STRIDE(arr3, 0) : \
                                            PyArray_STRIDE(arr3, \
                                                PyArray_NDIM(arr3)-1))); \
                }
#define PyArray_TRIVIALLY_ITERABLE (   arr)
Value:
#define PyArray_TRIVIALLY_ITERABLE_PAIR (   arr1,
  arr2 
)
Value:
(\
                    PyArray_TRIVIALLY_ITERABLE(arr1) && \
                        (PyArray_NDIM(arr2) == 0 || \
                         PyArray_EQUIVALENTLY_ITERABLE(arr1, arr2) || \
                         (PyArray_NDIM(arr1) == 0 && \
                             PyArray_TRIVIALLY_ITERABLE(arr2) \
                         ) \
                        ) \
                    )
#define PyArray_TRIVIALLY_ITERABLE_TRIPLE (   arr1,
  arr2,
  arr3 
)
Value:
(\
                PyArray_TRIVIALLY_ITERABLE(arr1) && \
                    ((PyArray_NDIM(arr2) == 0 && \
                        (PyArray_NDIM(arr3) == 0 || \
                            PyArray_EQUIVALENTLY_ITERABLE(arr1, arr3) \
                        ) \
                     ) || \
                     (PyArray_EQUIVALENTLY_ITERABLE(arr1, arr2) && \
                        (PyArray_NDIM(arr3) == 0 || \
                            PyArray_EQUIVALENTLY_ITERABLE(arr1, arr3) \
                        ) \
                     ) || \
                     (PyArray_NDIM(arr1) == 0 && \
                        PyArray_TRIVIALLY_ITERABLE(arr2) && \
                            (PyArray_NDIM(arr3) == 0 || \
                                PyArray_EQUIVALENTLY_ITERABLE(arr2, arr3) \
                            ) \
                     ) \
                    ) \
                )

Typedef Documentation

typedef void( PyArray_StridedTransferFn)(char *dst, npy_intp dst_stride, char *src, npy_intp src_stride, npy_intp N, npy_intp src_itemsize, void *transferdata)
NOTE: This API should remain private for the time being, to allow
for further refinement. I think the 'aligned' mechanism needs changing, for example.
This function pointer is for functions that transfer an arbitrarily strided input to a an arbitrarily strided output. It may be a fully general function, or a specialized function when the strides or item size have special values.
Examples of transfer functions are a straight copy, a byte-swap, and a casting operation,
The 'transferdata' parameter is slightly special, and must always contain pointer to deallocation and copying routines at its beginning. The function PyArray_FreeStridedTransferData should be used to deallocate such pointers, and calls the first function pointer, while the function PyArray_CopyStridedTransferData should be used to copy it.

Function Documentation

NPY_NO_EXPORT void* PyArray_CopyStridedTransferData ( void *  transferdata)
Copies a PyArray_StridedTransferFunction data object. See the comment with the function typedef for more details.
NPY_NO_EXPORT void PyArray_FreeStridedTransferData ( void *  transferdata)
Deallocates a PyArray_StridedTransferFunction data object. See the comment with the function typedef for more details.

Referenced by _field_transfer_data_copy(), _n_to_n_data_free(), and get_subarray_transfer_function().

NPY_NO_EXPORT int PyArray_GetDTypeTransferFunction ( int  aligned,
npy_intp  src_stride,
npy_intp  dst_stride,
PyArray_Descr src_dtype,
PyArray_Descr dst_dtype,
int  move_references,
PyArray_StridedTransferFn **  out_stransfer,
void **  out_transferdata,
int *  out_needs_api 
)
If it's possible, gives back a transfer function which casts and/or byte swaps data with the dtype 'src_dtype' into data with the dtype 'dst_dtype'. If the outtransferdata is populated with a non-NULL value, it must be deallocated with the PyArray_FreeStridedTransferData function when the transfer function is no longer required.

aligned:
Should be 1 if the src and dst pointers are always aligned, 0 otherwise.
src_stride:
Should be the src stride if it will always be the same, NPY_MAX_INTP otherwise.
dst_stride:
Should be the dst stride if it will always be the same, NPY_MAX_INTP otherwise.
src_dtype:
The data type of source data. If this is NULL, a transfer function which sets the destination to zeros is produced.
dst_dtype:
The data type of destination data. If this is NULL and move_references is 1, a transfer function which decrements source data references is produced.
move_references:
If 0, the destination data gets new reference ownership. If 1, the references from the source data are moved to the destination data.
out_stransfer:
The resulting transfer function is placed here.
out_transferdata:
The auxiliary data for the transfer function is placed here. When finished with the transfer function, the caller must call PyArray_FreeStridedTransferData on this data.
out_needs_api:
If this is non-NULL, and the transfer function produced needs to call into the (Python) API, this gets set to 1. This remains untouched if no API access is required.
WARNING: If you set move_references to 1, it is best that src_stride is
never zero when calling the transfer function. Otherwise, the first destination reference will get the value and all the rest will get NULL.
Returns NPY_SUCCEED or NPY_FAIL.
*************** MAIN DTYPE TRANSFER FUNCTION ******************

If one of the dtypes is NULL, we give back either a src decref function or a dst setzero function
Common special case - number -> number NBO cast
If there are no references and the data types are equivalent, return a simple copy
We can't pass through the aligned flag because it's not appropriate. Consider a size-8 string, it will say it's aligned because strings only need alignment 1, but the copy function wants to know if it's alignment 8.

TODO: Change align from a flag to a "best power of 2 alignment"
which holds the strongest alignment value for all the data which will be used.
First look at the possibilities of just a copy or swap
A custom data type requires that we use its copy/swap
If the sizes and kinds are identical, but they're different custom types, then get a cast function
The special types, which have no byte-order
This is a straight copy
This is a straight copy + byte swap
This is a straight copy + element pair byte swap
Handle subarrays
Handle fields
Check for different-sized strings, unicodes, or voids
Otherwise a cast is necessary

Referenced by _strided_to_strided_subarray_broadcast_withrefs(), and get_n_to_n_transfer_function().

NPY_NO_EXPORT PyArray_StridedTransferFn* PyArray_GetStridedCopyFn ( npy_intp  aligned,
npy_intp  src_stride,
npy_intp  dst_stride,
npy_intp  itemsize 
)
Gives back a function pointer to a specialized function for copying strided memory. Returns NULL if there is a problem with the inputs.

aligned:
Should be 1 if the src and dst pointers are always aligned, 0 otherwise.
src_stride:
Should be the src stride if it will always be the same, NPY_MAX_INTP otherwise.
dst_stride:
Should be the dst stride if it will always be the same, NPY_MAX_INTP otherwise.
itemsize:
Should be the item size if it will always be the same, 0 otherwise.

Skip the "unaligned" versions on CPUs which support unaligned memory accesses.

<

!NPY_USE_UNALIGNED_ACCESS
contiguous dst
constant src
begin repeat
#elsize = 1, 2, 4, 8, 16#
end repeat*
contiguous src
general src
begin repeat
#elsize = 1, 2, 4, 8, 16#
end repeat*
general dst
constant src
begin repeat
#elsize = 1, 2, 4, 8, 16#
end repeat*
contiguous src
begin repeat
#elsize = 1, 2, 4, 8, 16#
end repeat*
begin repeat
#elsize = 1, 2, 4, 8, 16#
end repeat*
contiguous dst
contiguous src
general src
begin repeat
#elsize = 2, 4, 8, 16#
end repeat*
general dst
contiguous src
begin repeat
#elsize = 2, 4, 8, 16#
end repeat*
general src
begin repeat
#elsize = 2, 4, 8, 16#
end repeat*

NPY_NO_EXPORT PyArray_StridedTransferFn* PyArray_GetStridedCopySwapFn ( npy_intp  aligned,
npy_intp  src_stride,
npy_intp  dst_stride,
npy_intp  itemsize 
)
Gives back a function pointer to a specialized function for copying and swapping strided memory. This assumes each element is a single value to be swapped.
For information on the 'aligned', 'src_stride' and 'dst_stride' parameters see above.
Parameters are as for PyArray_GetStridedCopyFn.
NPY_NO_EXPORT PyArray_StridedTransferFn* PyArray_GetStridedCopySwapPairFn ( npy_intp  aligned,
npy_intp  src_stride,
npy_intp  dst_stride,
npy_intp  itemsize 
)
Gives back a function pointer to a specialized function for copying and swapping strided memory. This assumes each element is a pair of values, each of which needs to be swapped.
For information on the 'aligned', 'src_stride' and 'dst_stride' parameters see above.
Parameters are as for PyArray_GetStridedCopyFn.
NPY_NO_EXPORT PyArray_StridedTransferFn* PyArray_GetStridedNumericCastFn ( npy_intp  aligned,
npy_intp  src_stride,
npy_intp  dst_stride,
int  src_type_num,
int  dst_type_num 
)
For casts between built-in numeric types, this produces a function pointer for casting from src_type_num to dst_type_num. If a conversion is unsupported, returns NULL without setting a Python exception.
end repeat*
******* STRIDED CASTING SPECIALIZED FUNCTIONS ********
begin repeat <blockquote>

#NAME1 = BOOL,
UBYTE, USHORT, UINT, ULONG, ULONGLONG, BYTE, SHORT, INT, LONG, LONGLONG, HALF, FLOAT, DOUBLE, LONGDOUBLE, CFLOAT, CDOUBLE, CLONGDOUBLE#
#name1 = bool,
ubyte, ushort, uint, ulong, ulonglong, byte, short, int, long, longlong, half, float, double, longdouble, cfloat, cdouble, clongdouble#
#rname1 = bool,
ubyte, ushort, uint, ulong, ulonglong, byte, short, int, long, longlong, half, float, double, longdouble, float, double, longdouble#
System Message: WARNING/2 (<string>, line 18) Definition list ends without a blank line; unexpected unindent.
#is_bool1 = 1, 0*17# #is_half1 = 0*11, 1, 0*6# #is_float1 = 0*12, 1, 0, 0, 1, 0, 0# #is_double1 = 0*13, 1, 0, 0, 1, 0# #is_complex1 = 0*15, 1*3# </blockquote>
begin repeat1 <blockquote>

#NAME2 = BOOL,
UBYTE, USHORT, UINT, ULONG, ULONGLONG, BYTE, SHORT, INT, LONG, LONGLONG, HALF, FLOAT, DOUBLE, LONGDOUBLE, CFLOAT, CDOUBLE, CLONGDOUBLE#
#name2 = bool,
ubyte, ushort, uint, ulong, ulonglong, byte, short, int, long, longlong, half, float, double, longdouble, cfloat, cdouble, clongdouble#
#rname2 = bool,
ubyte, ushort, uint, ulong, ulonglong, byte, short, int, long, longlong, half, float, double, longdouble, float, double, longdouble#
System Message: WARNING/2 (<string>, line 18) Definition list ends without a blank line; unexpected unindent.
#is_bool2 = 1, 0*17# #is_half2 = 0*11, 1, 0*6# #is_float2 = 0*12, 1, 0, 0, 1, 0, 0# #is_double2 = 0*13, 1, 0, 0, 1, 0# #is_complex2 = 0*15, 1*3# </blockquote>
begin repeat2
#prefix = _aligned,,_aligned_contig,_contig# #aligned = 1,0,1,0# #contig = 0,0,1,1#
end repeat2*
end repeat1*
end repeat*

begin repeat <blockquote>

#NAME1 = BOOL,
UBYTE, USHORT, UINT, ULONG, ULONGLONG, BYTE, SHORT, INT, LONG, LONGLONG, HALF, FLOAT, DOUBLE, LONGDOUBLE, CFLOAT, CDOUBLE, CLONGDOUBLE#
#name1 = bool,
ubyte, ushort, uint, ulong, ulonglong, byte, short, int, long, longlong, half, float, double, longdouble, cfloat, cdouble, clongdouble#

</blockquote>

printf("test fn d - second dn", NPY_&#64;NAME1&#64;, dst_type_num);
begin repeat1 <blockquote>

#NAME2 = BOOL,
UBYTE, USHORT, UINT, ULONG, ULONGLONG, BYTE, SHORT, INT, LONG, LONGLONG, HALF, FLOAT, DOUBLE, LONGDOUBLE, CFLOAT, CDOUBLE, CLONGDOUBLE#
#name2 = bool,
ubyte, ushort, uint, ulong, ulonglong, byte, short, int, long, longlong, half, float, double, longdouble, cfloat, cdouble, clongdouble#

</blockquote>

printf("ret fn d dn", NPY_&#64;NAME1&#64;, NPY_&#64;NAME2&#64;);
end repeat1*
printf("switched test fn d - second dn", NPY_&#64;NAME1&#64;, dst_type_num);
end repeat*

NPY_NO_EXPORT int PyArray_GetStridedZeroPadCopyFn ( int  aligned,
npy_intp  src_stride,
npy_intp  dst_stride,
npy_intp  src_itemsize,
npy_intp  dst_itemsize,
PyArray_StridedTransferFn **  outstransfer,
void **  outtransferdata 
)
Gives back a transfer function and transfer data pair which copies the data from source to dest, truncating it if the data doesn't fit, and padding with zero bytes if there's too much space.
For information on the 'aligned', 'src_stride' and 'dst_stride' parameters see above.
Returns NPY_SUCCEED or NPY_FAIL
NPY_NO_EXPORT npy_intp PyArray_TransferNDimToStrided ( npy_intp  ndim,
char *  dst,
npy_intp  dst_stride,
char *  src,
npy_intp src_strides,
npy_intp  src_strides_inc,
npy_intp coords,
npy_intp  coords_inc,
npy_intp shape,
npy_intp  shape_inc,
npy_intp  count,
npy_intp  src_itemsize,
PyArray_StridedTransferFn stransfer,
void *  data 
)
These two functions copy or convert the data of an n-dimensional array to/from a 1-dimensional strided buffer. These functions will only call 'stransfer' with the provided dst_stride/src_stride and dst_strides[0]/src_strides[0], so the caller can use those values to specialize the function.
The return value is the number of elements it couldn't copy. A return value of 0 means all elements were copied, a larger value means the end of the n-dimensional array was reached before 'count' elements were copied.

ndim:
The number of dimensions of the n-dimensional array.
dst/src:
The destination or src starting pointer.
dst_stride/src_stride:
The stride of the 1-dimensional strided buffer
dst_strides/src_strides:
The strides of the n-dimensional array.
dst_strides_inc/src_strides_inc:
How much to add to the ..._strides pointer to get to the next stride.
coords:
The starting coordinates in the n-dimensional array.
coords_inc:
How much to add to the coords pointer to get to the next coordinate.
shape:
The shape of the n-dimensional array.
shape_inc:
How much to add to the shape pointer to get to the next shape entry.
count:
How many elements to transfer
src_itemsize:
How big each element is. If transfering between elements of different sizes, for example a casting operation, the 'stransfer' function should be specialized for that, in which case 'stransfer' will use this parameter as the source item size.
stransfer:
The strided transfer function.
transferdata:
An auxiliary data pointer passed to the strided transfer function. If a non-NULL value is returned, it must be deallocated with the function PyArray_FreeStridedTransferData.
************ PRIMITIVE FLAT TO/FROM NDIM FUNCTIONS *************

Finish off dimension 0
If it's 1-dimensional, there's no more to copy
Adjust the src and dst pointers
Finish off dimension 1
If it's 2-dimensional, there's no more to copy
General-case loop for everything else
Iteration structure for dimensions 2 and up
Copy the coordinates and shape
Adjust the src pointer from the dimension 0 and 1 loop
Increment to the next coordinate
If the last dimension rolled over, we're done
A loop for dimensions 0 and 1

NPY_NO_EXPORT npy_intp PyArray_TransferStridedToNDim ( npy_intp  ndim,
char *  dst,
npy_intp dst_strides,
npy_intp  dst_strides_inc,
char *  src,
npy_intp  src_stride,
npy_intp coords,
npy_intp  coords_inc,
npy_intp shape,
npy_intp  shape_inc,
npy_intp  count,
npy_intp  src_itemsize,
PyArray_StridedTransferFn stransfer,
void *  transferdata 
)

Finish off dimension 0
If it's 1-dimensional, there's no more to copy
Adjust the src and dst pointers
Finish off dimension 1
If it's 2-dimensional, there's no more to copy
General-case loop for everything else
Iteration structure for dimensions 2 and up
Copy the coordinates and shape
Adjust the dst pointer from the dimension 0 and 1 loop
Increment to the next coordinate
If the last dimension rolled over, we're done
A loop for dimensions 0 and 1

Referenced by npyiter_coalesce_axes().