numpy 2.0.0
|
00001 #ifndef __LOWLEVEL_STRIDED_LOOPS_H 00002 #define __LOWLEVEL_STRIDED_LOOPS_H 00003 00004 /* 00005 * NOTE: This API should remain private for the time being, to allow 00006 * for further refinement. I think the 'aligned' mechanism 00007 * needs changing, for example. 00008 */ 00009 00010 /* 00011 * This function pointer is for functions that transfer an arbitrarily strided 00012 * input to a an arbitrarily strided output. It may be a fully general 00013 * function, or a specialized function when the strides or item size 00014 * have special values. 00015 * 00016 * Examples of transfer functions are a straight copy, a byte-swap, 00017 * and a casting operation, 00018 * 00019 * The 'transferdata' parameter is slightly special, and must always contain 00020 * pointer to deallocation and copying routines at its beginning. The function 00021 * PyArray_FreeStridedTransferData should be used to deallocate such 00022 * pointers, and calls the first function pointer, while the function 00023 * PyArray_CopyStridedTransferData should be used to copy it. 00024 * 00025 */ 00026 typedef void (PyArray_StridedTransferFn)(char *dst, npy_intp dst_stride, 00027 char *src, npy_intp src_stride, 00028 npy_intp N, npy_intp src_itemsize, 00029 void *transferdata); 00030 00031 /* 00032 * Deallocates a PyArray_StridedTransferFunction data object. See 00033 * the comment with the function typedef for more details. 00034 */ 00035 NPY_NO_EXPORT void 00036 PyArray_FreeStridedTransferData(void *transferdata); 00037 00038 /* 00039 * Copies a PyArray_StridedTransferFunction data object. See 00040 * the comment with the function typedef for more details. 00041 */ 00042 NPY_NO_EXPORT void * 00043 PyArray_CopyStridedTransferData(void *transferdata); 00044 00045 /* 00046 * Gives back a function pointer to a specialized function for copying 00047 * strided memory. Returns NULL if there is a problem with the inputs. 00048 * 00049 * aligned: 00050 * Should be 1 if the src and dst pointers are always aligned, 00051 * 0 otherwise. 00052 * src_stride: 00053 * Should be the src stride if it will always be the same, 00054 * NPY_MAX_INTP otherwise. 00055 * dst_stride: 00056 * Should be the dst stride if it will always be the same, 00057 * NPY_MAX_INTP otherwise. 00058 * itemsize: 00059 * Should be the item size if it will always be the same, 0 otherwise. 00060 * 00061 */ 00062 NPY_NO_EXPORT PyArray_StridedTransferFn * 00063 PyArray_GetStridedCopyFn(npy_intp aligned, npy_intp src_stride, 00064 npy_intp dst_stride, npy_intp itemsize); 00065 00066 /* 00067 * Gives back a function pointer to a specialized function for copying 00068 * and swapping strided memory. This assumes each element is a single 00069 * value to be swapped. 00070 * 00071 * For information on the 'aligned', 'src_stride' and 'dst_stride' parameters 00072 * see above. 00073 * 00074 * Parameters are as for PyArray_GetStridedCopyFn. 00075 */ 00076 NPY_NO_EXPORT PyArray_StridedTransferFn * 00077 PyArray_GetStridedCopySwapFn(npy_intp aligned, npy_intp src_stride, 00078 npy_intp dst_stride, npy_intp itemsize); 00079 00080 /* 00081 * Gives back a function pointer to a specialized function for copying 00082 * and swapping strided memory. This assumes each element is a pair 00083 * of values, each of which needs to be swapped. 00084 * 00085 * For information on the 'aligned', 'src_stride' and 'dst_stride' parameters 00086 * see above. 00087 * 00088 * Parameters are as for PyArray_GetStridedCopyFn. 00089 */ 00090 NPY_NO_EXPORT PyArray_StridedTransferFn * 00091 PyArray_GetStridedCopySwapPairFn(npy_intp aligned, npy_intp src_stride, 00092 npy_intp dst_stride, npy_intp itemsize); 00093 00094 /* 00095 * Gives back a transfer function and transfer data pair which copies 00096 * the data from source to dest, truncating it if the data doesn't 00097 * fit, and padding with zero bytes if there's too much space. 00098 * 00099 * For information on the 'aligned', 'src_stride' and 'dst_stride' parameters 00100 * see above. 00101 * 00102 * Returns NPY_SUCCEED or NPY_FAIL 00103 */ 00104 NPY_NO_EXPORT int 00105 PyArray_GetStridedZeroPadCopyFn(int aligned, 00106 npy_intp src_stride, npy_intp dst_stride, 00107 npy_intp src_itemsize, npy_intp dst_itemsize, 00108 PyArray_StridedTransferFn **outstransfer, 00109 void **outtransferdata); 00110 00111 /* 00112 * For casts between built-in numeric types, 00113 * this produces a function pointer for casting from src_type_num 00114 * to dst_type_num. If a conversion is unsupported, returns NULL 00115 * without setting a Python exception. 00116 */ 00117 NPY_NO_EXPORT PyArray_StridedTransferFn * 00118 PyArray_GetStridedNumericCastFn(npy_intp aligned, npy_intp src_stride, 00119 npy_intp dst_stride, 00120 int src_type_num, int dst_type_num); 00121 00122 /* 00123 * If it's possible, gives back a transfer function which casts and/or 00124 * byte swaps data with the dtype 'src_dtype' into data with the dtype 00125 * 'dst_dtype'. If the outtransferdata is populated with a non-NULL value, 00126 * it must be deallocated with the ``PyArray_FreeStridedTransferData`` 00127 * function when the transfer function is no longer required. 00128 * 00129 * aligned: 00130 * Should be 1 if the src and dst pointers are always aligned, 00131 * 0 otherwise. 00132 * src_stride: 00133 * Should be the src stride if it will always be the same, 00134 * NPY_MAX_INTP otherwise. 00135 * dst_stride: 00136 * Should be the dst stride if it will always be the same, 00137 * NPY_MAX_INTP otherwise. 00138 * src_dtype: 00139 * The data type of source data. If this is NULL, a transfer 00140 * function which sets the destination to zeros is produced. 00141 * dst_dtype: 00142 * The data type of destination data. If this is NULL and 00143 * move_references is 1, a transfer function which decrements 00144 * source data references is produced. 00145 * move_references: 00146 * If 0, the destination data gets new reference ownership. 00147 * If 1, the references from the source data are moved to 00148 * the destination data. 00149 * out_stransfer: 00150 * The resulting transfer function is placed here. 00151 * out_transferdata: 00152 * The auxiliary data for the transfer function is placed here. 00153 * When finished with the transfer function, the caller must call 00154 * ``PyArray_FreeStridedTransferData`` on this data. 00155 * out_needs_api: 00156 * If this is non-NULL, and the transfer function produced needs 00157 * to call into the (Python) API, this gets set to 1. This 00158 * remains untouched if no API access is required. 00159 * 00160 * WARNING: If you set move_references to 1, it is best that src_stride is 00161 * never zero when calling the transfer function. Otherwise, the 00162 * first destination reference will get the value and all the rest 00163 * will get NULL. 00164 * 00165 * Returns NPY_SUCCEED or NPY_FAIL. 00166 */ 00167 NPY_NO_EXPORT int 00168 PyArray_GetDTypeTransferFunction(int aligned, 00169 npy_intp src_stride, npy_intp dst_stride, 00170 PyArray_Descr *src_dtype, PyArray_Descr *dst_dtype, 00171 int move_references, 00172 PyArray_StridedTransferFn **out_stransfer, 00173 void **out_transferdata, 00174 int *out_needs_api); 00175 00176 /* 00177 * These two functions copy or convert the data of an n-dimensional array 00178 * to/from a 1-dimensional strided buffer. These functions will only call 00179 * 'stransfer' with the provided dst_stride/src_stride and 00180 * dst_strides[0]/src_strides[0], so the caller can use those values to 00181 * specialize the function. 00182 * 00183 * The return value is the number of elements it couldn't copy. A return value 00184 * of 0 means all elements were copied, a larger value means the end of 00185 * the n-dimensional array was reached before 'count' elements were copied. 00186 * 00187 * ndim: 00188 * The number of dimensions of the n-dimensional array. 00189 * dst/src: 00190 * The destination or src starting pointer. 00191 * dst_stride/src_stride: 00192 * The stride of the 1-dimensional strided buffer 00193 * dst_strides/src_strides: 00194 * The strides of the n-dimensional array. 00195 * dst_strides_inc/src_strides_inc: 00196 * How much to add to the ..._strides pointer to get to the next stride. 00197 * coords: 00198 * The starting coordinates in the n-dimensional array. 00199 * coords_inc: 00200 * How much to add to the coords pointer to get to the next coordinate. 00201 * shape: 00202 * The shape of the n-dimensional array. 00203 * shape_inc: 00204 * How much to add to the shape pointer to get to the next shape entry. 00205 * count: 00206 * How many elements to transfer 00207 * src_itemsize: 00208 * How big each element is. If transfering between elements of different 00209 * sizes, for example a casting operation, the 'stransfer' function 00210 * should be specialized for that, in which case 'stransfer' will use 00211 * this parameter as the source item size. 00212 * stransfer: 00213 * The strided transfer function. 00214 * transferdata: 00215 * An auxiliary data pointer passed to the strided transfer function. 00216 * If a non-NULL value is returned, it must be deallocated with the 00217 * function PyArray_FreeStridedTransferData. 00218 */ 00219 NPY_NO_EXPORT npy_intp 00220 PyArray_TransferNDimToStrided(npy_intp ndim, 00221 char *dst, npy_intp dst_stride, 00222 char *src, npy_intp *src_strides, npy_intp src_strides_inc, 00223 npy_intp *coords, npy_intp coords_inc, 00224 npy_intp *shape, npy_intp shape_inc, 00225 npy_intp count, npy_intp src_itemsize, 00226 PyArray_StridedTransferFn *stransfer, 00227 void *transferdata); 00228 00229 NPY_NO_EXPORT npy_intp 00230 PyArray_TransferStridedToNDim(npy_intp ndim, 00231 char *dst, npy_intp *dst_strides, npy_intp dst_strides_inc, 00232 char *src, npy_intp src_stride, 00233 npy_intp *coords, npy_intp coords_inc, 00234 npy_intp *shape, npy_intp shape_inc, 00235 npy_intp count, npy_intp src_itemsize, 00236 PyArray_StridedTransferFn *stransfer, 00237 void *transferdata); 00238 00239 /* 00240 * TRIVIAL ITERATION 00241 * 00242 * In some cases when the iteration order isn't important, iteration over 00243 * arrays is trivial. This is the case when: 00244 * * The array has 0 or 1 dimensions. 00245 * * The array is C or Fortran contiguous. 00246 * Use of an iterator can be skipped when this occurs. These macros assist 00247 * in detecting and taking advantage of the situation. Note that it may 00248 * be worthwhile to further check if the stride is a contiguous stride 00249 * and take advantage of that. 00250 * 00251 * Here is example code for a single array: 00252 * 00253 * if (PyArray_TRIVIALLY_ITERABLE(self) { 00254 * char *data; 00255 * npy_intp count, stride; 00256 * 00257 * PyArray_PREPARE_TRIVIAL_ITERATION(self, count, data, stride); 00258 * 00259 * while (count--) { 00260 * // Use the data pointer 00261 * 00262 * data += stride; 00263 * } 00264 * } 00265 * else { 00266 * // Create iterator, etc... 00267 * } 00268 * 00269 * Here is example code for a pair of arrays: 00270 * 00271 * if (PyArray_TRIVIALLY_ITERABLE_PAIR(a1, a2) { 00272 * char *data1, *data2; 00273 * npy_intp count, stride1, stride2; 00274 * 00275 * PyArray_PREPARE_TRIVIAL_PAIR_ITERATION(a1, a2, count, 00276 * data1, data2, stride1, stride2); 00277 * 00278 * while (count--) { 00279 * // Use the data1 and data2 pointers 00280 * 00281 * data1 += stride1; 00282 * data2 += stride2; 00283 * } 00284 * } 00285 * else { 00286 * // Create iterator, etc... 00287 * } 00288 */ 00289 00290 /* 00291 * Note: Equivalently iterable macro requires one of arr1 or arr2 be 00292 * trivially iterable to be valid. 00293 */ 00294 #define PyArray_EQUIVALENTLY_ITERABLE(arr1, arr2) ( \ 00295 PyArray_NDIM(arr1) == PyArray_NDIM(arr2) && \ 00296 PyArray_CompareLists(PyArray_DIMS(arr1), \ 00297 PyArray_DIMS(arr2), \ 00298 PyArray_NDIM(arr1)) && \ 00299 (arr1->flags&(NPY_CONTIGUOUS|NPY_FORTRAN)) == \ 00300 (arr2->flags&(NPY_CONTIGUOUS|NPY_FORTRAN)) \ 00301 ) 00302 00303 #define PyArray_TRIVIALLY_ITERABLE(arr) ( \ 00304 PyArray_NDIM(arr) <= 1 || \ 00305 PyArray_CHKFLAGS(arr, NPY_CONTIGUOUS) || \ 00306 PyArray_CHKFLAGS(arr, NPY_FORTRAN) \ 00307 ) 00308 #define PyArray_PREPARE_TRIVIAL_ITERATION(arr, count, data, stride) \ 00309 count = PyArray_SIZE(arr), \ 00310 data = PyArray_BYTES(arr), \ 00311 stride = ((PyArray_NDIM(arr) == 0) ? 0 : \ 00312 (PyArray_CHKFLAGS(arr, NPY_FORTRAN) ? \ 00313 PyArray_STRIDE(arr, 0) : \ 00314 PyArray_STRIDE(arr, \ 00315 PyArray_NDIM(arr)-1))) 00316 00317 #define PyArray_TRIVIALLY_ITERABLE_PAIR(arr1, arr2) (\ 00318 PyArray_TRIVIALLY_ITERABLE(arr1) && \ 00319 (PyArray_NDIM(arr2) == 0 || \ 00320 PyArray_EQUIVALENTLY_ITERABLE(arr1, arr2) || \ 00321 (PyArray_NDIM(arr1) == 0 && \ 00322 PyArray_TRIVIALLY_ITERABLE(arr2) \ 00323 ) \ 00324 ) \ 00325 ) 00326 #define PyArray_PREPARE_TRIVIAL_PAIR_ITERATION(arr1, arr2, \ 00327 count, \ 00328 data1, data2, \ 00329 stride1, stride2) { \ 00330 npy_intp size1 = PyArray_SIZE(arr1); \ 00331 npy_intp size2 = PyArray_SIZE(arr2); \ 00332 count = ((size1 > size2) || size1 == 0) ? size1 : size2; \ 00333 data1 = PyArray_BYTES(arr1); \ 00334 data2 = PyArray_BYTES(arr2); \ 00335 stride1 = (size1 == 1 ? 0 : \ 00336 (PyArray_CHKFLAGS(arr1, NPY_FORTRAN) ? \ 00337 PyArray_STRIDE(arr1, 0) : \ 00338 PyArray_STRIDE(arr1, \ 00339 PyArray_NDIM(arr1)-1))); \ 00340 stride2 = (size2 == 1 ? 0 : \ 00341 (PyArray_CHKFLAGS(arr2, NPY_FORTRAN) ? \ 00342 PyArray_STRIDE(arr2, 0) : \ 00343 PyArray_STRIDE(arr2, \ 00344 PyArray_NDIM(arr2)-1))); \ 00345 } 00346 00347 #define PyArray_TRIVIALLY_ITERABLE_TRIPLE(arr1, arr2, arr3) (\ 00348 PyArray_TRIVIALLY_ITERABLE(arr1) && \ 00349 ((PyArray_NDIM(arr2) == 0 && \ 00350 (PyArray_NDIM(arr3) == 0 || \ 00351 PyArray_EQUIVALENTLY_ITERABLE(arr1, arr3) \ 00352 ) \ 00353 ) || \ 00354 (PyArray_EQUIVALENTLY_ITERABLE(arr1, arr2) && \ 00355 (PyArray_NDIM(arr3) == 0 || \ 00356 PyArray_EQUIVALENTLY_ITERABLE(arr1, arr3) \ 00357 ) \ 00358 ) || \ 00359 (PyArray_NDIM(arr1) == 0 && \ 00360 PyArray_TRIVIALLY_ITERABLE(arr2) && \ 00361 (PyArray_NDIM(arr3) == 0 || \ 00362 PyArray_EQUIVALENTLY_ITERABLE(arr2, arr3) \ 00363 ) \ 00364 ) \ 00365 ) \ 00366 ) 00367 00368 #define PyArray_PREPARE_TRIVIAL_TRIPLE_ITERATION(arr1, arr2, arr3, \ 00369 count, \ 00370 data1, data2, data3, \ 00371 stride1, stride2, stride3) { \ 00372 npy_intp size1 = PyArray_SIZE(arr1); \ 00373 npy_intp size2 = PyArray_SIZE(arr2); \ 00374 npy_intp size3 = PyArray_SIZE(arr3); \ 00375 count = ((size1 > size2) || size1 == 0) ? size1 : size2; \ 00376 count = ((size3 > count) || size3 == 0) ? size3 : count; \ 00377 data1 = PyArray_BYTES(arr1); \ 00378 data2 = PyArray_BYTES(arr2); \ 00379 data3 = PyArray_BYTES(arr3); \ 00380 stride1 = (size1 == 1 ? 0 : \ 00381 (PyArray_CHKFLAGS(arr1, NPY_FORTRAN) ? \ 00382 PyArray_STRIDE(arr1, 0) : \ 00383 PyArray_STRIDE(arr1, \ 00384 PyArray_NDIM(arr1)-1))); \ 00385 stride2 = (size2 == 1 ? 0 : \ 00386 (PyArray_CHKFLAGS(arr2, NPY_FORTRAN) ? \ 00387 PyArray_STRIDE(arr2, 0) : \ 00388 PyArray_STRIDE(arr2, \ 00389 PyArray_NDIM(arr2)-1))); \ 00390 stride3 = (size3 == 1 ? 0 : \ 00391 (PyArray_CHKFLAGS(arr3, NPY_FORTRAN) ? \ 00392 PyArray_STRIDE(arr3, 0) : \ 00393 PyArray_STRIDE(arr3, \ 00394 PyArray_NDIM(arr3)-1))); \ 00395 } 00396 00397 #endif