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 unary operations that input an 00012 * arbitrarily strided one-dimensional array segment and output 00013 * an arbitrarily strided array segment of the same size. 00014 * It may be a fully general function, or a specialized function 00015 * when the strides or item size have particular known values. 00016 * 00017 * Examples of unary operations are a straight copy, a byte-swap, 00018 * and a casting operation, 00019 * 00020 * The 'transferdata' parameter is slightly special, following a 00021 * generic auxiliary data pattern defined in ndarraytypes.h 00022 * Use NPY_AUXDATA_CLONE and NPY_AUXDATA_FREE to deal with this data. 00023 * 00024 */ 00025 typedef void (PyArray_StridedUnaryOp)(char *dst, npy_intp dst_stride, 00026 char *src, npy_intp src_stride, 00027 npy_intp N, npy_intp src_itemsize, 00028 NpyAuxData *transferdata); 00029 00030 /* 00031 * This is for pointers to functions which behave exactly as 00032 * for PyArray_StridedUnaryOp, but with an additional mask controlling 00033 * which values are transformed. 00034 * 00035 * In particular, the 'i'-th element is operated on if and only if 00036 * mask[i*mask_stride] is true. 00037 */ 00038 typedef void (PyArray_MaskedStridedUnaryOp)(char *dst, npy_intp dst_stride, 00039 char *src, npy_intp src_stride, 00040 npy_bool *mask, npy_intp mask_stride, 00041 npy_intp N, npy_intp src_itemsize, 00042 NpyAuxData *transferdata); 00043 00044 /* 00045 * This function pointer is for binary operations that input two 00046 * arbitrarily strided one-dimensional array segments and output 00047 * an arbitrarily strided array segment of the same size. 00048 * It may be a fully general function, or a specialized function 00049 * when the strides or item size have particular known values. 00050 * 00051 * Examples of binary operations are the basic arithmetic operations, 00052 * logical operators AND, OR, and many others. 00053 * 00054 * The 'transferdata' parameter is slightly special, following a 00055 * generic auxiliary data pattern defined in ndarraytypes.h 00056 * Use NPY_AUXDATA_CLONE and NPY_AUXDATA_FREE to deal with this data. 00057 * 00058 */ 00059 typedef void (PyArray_StridedBinaryOp)(char *dst, npy_intp dst_stride, 00060 char *src0, npy_intp src0_stride, 00061 char *src1, npy_intp src1_stride, 00062 npy_intp N, NpyAuxData *transferdata); 00063 00064 /* 00065 * Gives back a function pointer to a specialized function for copying 00066 * strided memory. Returns NULL if there is a problem with the inputs. 00067 * 00068 * aligned: 00069 * Should be 1 if the src and dst pointers are always aligned, 00070 * 0 otherwise. 00071 * src_stride: 00072 * Should be the src stride if it will always be the same, 00073 * NPY_MAX_INTP otherwise. 00074 * dst_stride: 00075 * Should be the dst stride if it will always be the same, 00076 * NPY_MAX_INTP otherwise. 00077 * itemsize: 00078 * Should be the item size if it will always be the same, 0 otherwise. 00079 * 00080 */ 00081 NPY_NO_EXPORT PyArray_StridedUnaryOp * 00082 PyArray_GetStridedCopyFn(int aligned, 00083 npy_intp src_stride, npy_intp dst_stride, 00084 npy_intp itemsize); 00085 00086 /* 00087 * Gives back a function pointer to a specialized function for copying 00088 * and swapping strided memory. This assumes each element is a single 00089 * value to be swapped. 00090 * 00091 * For information on the 'aligned', 'src_stride' and 'dst_stride' parameters 00092 * see above. 00093 * 00094 * Parameters are as for PyArray_GetStridedCopyFn. 00095 */ 00096 NPY_NO_EXPORT PyArray_StridedUnaryOp * 00097 PyArray_GetStridedCopySwapFn(int aligned, 00098 npy_intp src_stride, npy_intp dst_stride, 00099 npy_intp itemsize); 00100 00101 /* 00102 * Gives back a function pointer to a specialized function for copying 00103 * and swapping strided memory. This assumes each element is a pair 00104 * of values, each of which needs to be swapped. 00105 * 00106 * For information on the 'aligned', 'src_stride' and 'dst_stride' parameters 00107 * see above. 00108 * 00109 * Parameters are as for PyArray_GetStridedCopyFn. 00110 */ 00111 NPY_NO_EXPORT PyArray_StridedUnaryOp * 00112 PyArray_GetStridedCopySwapPairFn(int aligned, 00113 npy_intp src_stride, npy_intp dst_stride, 00114 npy_intp itemsize); 00115 00116 /* 00117 * Gives back a transfer function and transfer data pair which copies 00118 * the data from source to dest, truncating it if the data doesn't 00119 * fit, and padding with zero bytes if there's too much space. 00120 * 00121 * For information on the 'aligned', 'src_stride' and 'dst_stride' parameters 00122 * see above. 00123 * 00124 * Returns NPY_SUCCEED or NPY_FAIL 00125 */ 00126 NPY_NO_EXPORT int 00127 PyArray_GetStridedZeroPadCopyFn(int aligned, 00128 npy_intp src_stride, npy_intp dst_stride, 00129 npy_intp src_itemsize, npy_intp dst_itemsize, 00130 PyArray_StridedUnaryOp **outstransfer, 00131 NpyAuxData **outtransferdata); 00132 00133 /* 00134 * For casts between built-in numeric types, 00135 * this produces a function pointer for casting from src_type_num 00136 * to dst_type_num. If a conversion is unsupported, returns NULL 00137 * without setting a Python exception. 00138 */ 00139 NPY_NO_EXPORT PyArray_StridedUnaryOp * 00140 PyArray_GetStridedNumericCastFn(int aligned, 00141 npy_intp src_stride, npy_intp dst_stride, 00142 int src_type_num, int dst_type_num); 00143 00144 /* 00145 * Gets an operation which copies elements of the given dtype, 00146 * swapping if the dtype isn't in NBO. 00147 * 00148 * Returns NPY_SUCCEED or NPY_FAIL 00149 */ 00150 NPY_NO_EXPORT int 00151 PyArray_GetDTypeCopySwapFn(int aligned, 00152 npy_intp src_stride, npy_intp dst_stride, 00153 PyArray_Descr *dtype, 00154 PyArray_StridedUnaryOp **outstransfer, 00155 NpyAuxData **outtransferdata); 00156 00157 /* 00158 * If it's possible, gives back a transfer function which casts and/or 00159 * byte swaps data with the dtype 'src_dtype' into data with the dtype 00160 * 'dst_dtype'. If the outtransferdata is populated with a non-NULL value, 00161 * it must be deallocated with the NPY_AUXDATA_FREE 00162 * function when the transfer function is no longer required. 00163 * 00164 * aligned: 00165 * Should be 1 if the src and dst pointers are always aligned, 00166 * 0 otherwise. 00167 * src_stride: 00168 * Should be the src stride if it will always be the same, 00169 * NPY_MAX_INTP otherwise. 00170 * dst_stride: 00171 * Should be the dst stride if it will always be the same, 00172 * NPY_MAX_INTP otherwise. 00173 * src_dtype: 00174 * The data type of source data. If this is NULL, a transfer 00175 * function which sets the destination to zeros is produced. 00176 * dst_dtype: 00177 * The data type of destination data. If this is NULL and 00178 * move_references is 1, a transfer function which decrements 00179 * source data references is produced. 00180 * move_references: 00181 * If 0, the destination data gets new reference ownership. 00182 * If 1, the references from the source data are moved to 00183 * the destination data. 00184 * out_stransfer: 00185 * The resulting transfer function is placed here. 00186 * out_transferdata: 00187 * The auxiliary data for the transfer function is placed here. 00188 * When finished with the transfer function, the caller must call 00189 * NPY_AUXDATA_FREE on this data. 00190 * out_needs_api: 00191 * If this is non-NULL, and the transfer function produced needs 00192 * to call into the (Python) API, this gets set to 1. This 00193 * remains untouched if no API access is required. 00194 * 00195 * WARNING: If you set move_references to 1, it is best that src_stride is 00196 * never zero when calling the transfer function. Otherwise, the 00197 * first destination reference will get the value and all the rest 00198 * will get NULL. 00199 * 00200 * Returns NPY_SUCCEED or NPY_FAIL. 00201 */ 00202 NPY_NO_EXPORT int 00203 PyArray_GetDTypeTransferFunction(int aligned, 00204 npy_intp src_stride, npy_intp dst_stride, 00205 PyArray_Descr *src_dtype, PyArray_Descr *dst_dtype, 00206 int move_references, 00207 PyArray_StridedUnaryOp **out_stransfer, 00208 NpyAuxData **out_transferdata, 00209 int *out_needs_api); 00210 00211 /* 00212 * This is identical to PyArray_GetDTypeTransferFunction, but returns a 00213 * transfer function which also takes a mask as a parameter. The mask is used 00214 * to determine which values to copy, and data is transfered exactly when 00215 * mask[i*mask_stride] is true. 00216 * 00217 * If move_references is true, values which are not copied to the 00218 * destination will still have their source reference decremented. 00219 * 00220 * If mask_dtype is NPY_BOOL or NPY_UINT8, each full element is either 00221 * transferred or not according to the mask as described above. If 00222 * dst_dtype and mask_dtype are both struct dtypes, their names must 00223 * match exactly, and the dtype of each leaf field in mask_dtype must 00224 * be either NPY_BOOL or NPY_UINT8. 00225 */ 00226 NPY_NO_EXPORT int 00227 PyArray_GetMaskedDTypeTransferFunction(int aligned, 00228 npy_intp src_stride, 00229 npy_intp dst_stride, 00230 npy_intp mask_stride, 00231 PyArray_Descr *src_dtype, 00232 PyArray_Descr *dst_dtype, 00233 PyArray_Descr *mask_dtype, 00234 int move_references, 00235 PyArray_MaskedStridedUnaryOp **out_stransfer, 00236 NpyAuxData **out_transferdata, 00237 int *out_needs_api); 00238 00239 /* 00240 * Casts the specified number of elements from 'src' with data type 00241 * 'src_dtype' to 'dst' with 'dst_dtype'. See 00242 * PyArray_GetDTypeTransferFunction for more details. 00243 * 00244 * Returns NPY_SUCCEED or NPY_FAIL. 00245 */ 00246 NPY_NO_EXPORT int 00247 PyArray_CastRawArrays(npy_intp count, 00248 char *src, char *dst, 00249 npy_intp src_stride, npy_intp dst_stride, 00250 PyArray_Descr *src_dtype, PyArray_Descr *dst_dtype, 00251 int move_references); 00252 00253 /* 00254 * These two functions copy or convert the data of an n-dimensional array 00255 * to/from a 1-dimensional strided buffer. These functions will only call 00256 * 'stransfer' with the provided dst_stride/src_stride and 00257 * dst_strides[0]/src_strides[0], so the caller can use those values to 00258 * specialize the function. 00259 * 00260 * The return value is the number of elements it couldn't copy. A return value 00261 * of 0 means all elements were copied, a larger value means the end of 00262 * the n-dimensional array was reached before 'count' elements were copied. 00263 * 00264 * ndim: 00265 * The number of dimensions of the n-dimensional array. 00266 * dst/src/mask: 00267 * The destination, source or mask starting pointer. 00268 * dst_stride/src_stride/mask_stride: 00269 * The stride of the 1-dimensional strided buffer 00270 * dst_strides/src_strides: 00271 * The strides of the n-dimensional array. 00272 * dst_strides_inc/src_strides_inc: 00273 * How much to add to the ..._strides pointer to get to the next stride. 00274 * coords: 00275 * The starting coordinates in the n-dimensional array. 00276 * coords_inc: 00277 * How much to add to the coords pointer to get to the next coordinate. 00278 * shape: 00279 * The shape of the n-dimensional array. 00280 * shape_inc: 00281 * How much to add to the shape pointer to get to the next shape entry. 00282 * count: 00283 * How many elements to transfer 00284 * src_itemsize: 00285 * How big each element is. If transfering between elements of different 00286 * sizes, for example a casting operation, the 'stransfer' function 00287 * should be specialized for that, in which case 'stransfer' will use 00288 * this parameter as the source item size. 00289 * stransfer: 00290 * The strided transfer function. 00291 * transferdata: 00292 * An auxiliary data pointer passed to the strided transfer function. 00293 * This follows the conventions of NpyAuxData objects. 00294 */ 00295 NPY_NO_EXPORT npy_intp 00296 PyArray_TransferNDimToStrided(npy_intp ndim, 00297 char *dst, npy_intp dst_stride, 00298 char *src, npy_intp *src_strides, npy_intp src_strides_inc, 00299 npy_intp *coords, npy_intp coords_inc, 00300 npy_intp *shape, npy_intp shape_inc, 00301 npy_intp count, npy_intp src_itemsize, 00302 PyArray_StridedUnaryOp *stransfer, 00303 NpyAuxData *transferdata); 00304 00305 NPY_NO_EXPORT npy_intp 00306 PyArray_TransferStridedToNDim(npy_intp ndim, 00307 char *dst, npy_intp *dst_strides, npy_intp dst_strides_inc, 00308 char *src, npy_intp src_stride, 00309 npy_intp *coords, npy_intp coords_inc, 00310 npy_intp *shape, npy_intp shape_inc, 00311 npy_intp count, npy_intp src_itemsize, 00312 PyArray_StridedUnaryOp *stransfer, 00313 NpyAuxData *transferdata); 00314 00315 NPY_NO_EXPORT npy_intp 00316 PyArray_TransferMaskedStridedToNDim(npy_intp ndim, 00317 char *dst, npy_intp *dst_strides, npy_intp dst_strides_inc, 00318 char *src, npy_intp src_stride, 00319 npy_bool *mask, npy_intp mask_stride, 00320 npy_intp *coords, npy_intp coords_inc, 00321 npy_intp *shape, npy_intp shape_inc, 00322 npy_intp count, npy_intp src_itemsize, 00323 PyArray_MaskedStridedUnaryOp *stransfer, 00324 NpyAuxData *data); 00325 00326 /* 00327 * Prepares shape and strides for a simple raw array iteration. 00328 * This sorts the strides into FORTRAN order, reverses any negative 00329 * strides, then coalesces axes where possible. The results are 00330 * filled in the output parameters. 00331 * 00332 * This is intended for simple, lightweight iteration over arrays 00333 * where no buffering of any kind is needed, and the array may 00334 * not be stored as a PyArrayObject. 00335 * 00336 * You can use this together with NPY_RAW_ITER_START and 00337 * NPY_RAW_ITER_ONE_NEXT to handle the looping boilerplate of everything 00338 * but the innermost loop (which is for idim == 0). 00339 * 00340 * Returns 0 on success, -1 on failure. 00341 */ 00342 NPY_NO_EXPORT int 00343 PyArray_PrepareOneRawArrayIter(int ndim, npy_intp *shape, 00344 char *data, npy_intp *strides, 00345 int *out_ndim, npy_intp *out_shape, 00346 char **out_data, npy_intp *out_strides); 00347 00348 /* 00349 * The same as PyArray_PrepareOneRawArrayIter, but for two 00350 * operands instead of one. Any broadcasting of the two operands 00351 * should have already been done before calling this function, 00352 * as the ndim and shape is only specified once for both operands. 00353 * 00354 * Only the strides of the first operand are used to reorder 00355 * the dimensions, no attempt to consider all the strides together 00356 * is made, as is done in the NpyIter object. 00357 * 00358 * You can use this together with NPY_RAW_ITER_START and 00359 * NPY_RAW_ITER_TWO_NEXT to handle the looping boilerplate of everything 00360 * but the innermost loop (which is for idim == 0). 00361 * 00362 * Returns 0 on success, -1 on failure. 00363 */ 00364 NPY_NO_EXPORT int 00365 PyArray_PrepareTwoRawArrayIter(int ndim, npy_intp *shape, 00366 char *dataA, npy_intp *stridesA, 00367 char *dataB, npy_intp *stridesB, 00368 int *out_ndim, npy_intp *out_shape, 00369 char **out_dataA, npy_intp *out_stridesA, 00370 char **out_dataB, npy_intp *out_stridesB); 00371 00372 /* 00373 * The same as PyArray_PrepareOneRawArrayIter, but for three 00374 * operands instead of one. Any broadcasting of the three operands 00375 * should have already been done before calling this function, 00376 * as the ndim and shape is only specified once for all operands. 00377 * 00378 * Only the strides of the first operand are used to reorder 00379 * the dimensions, no attempt to consider all the strides together 00380 * is made, as is done in the NpyIter object. 00381 * 00382 * You can use this together with NPY_RAW_ITER_START and 00383 * NPY_RAW_ITER_THREE_NEXT to handle the looping boilerplate of everything 00384 * but the innermost loop (which is for idim == 0). 00385 * 00386 * Returns 0 on success, -1 on failure. 00387 */ 00388 NPY_NO_EXPORT int 00389 PyArray_PrepareThreeRawArrayIter(int ndim, npy_intp *shape, 00390 char *dataA, npy_intp *stridesA, 00391 char *dataB, npy_intp *stridesB, 00392 char *dataC, npy_intp *stridesC, 00393 int *out_ndim, npy_intp *out_shape, 00394 char **out_dataA, npy_intp *out_stridesA, 00395 char **out_dataB, npy_intp *out_stridesB, 00396 char **out_dataC, npy_intp *out_stridesC); 00397 00398 /* Start raw iteration */ 00399 #define NPY_RAW_ITER_START(idim, ndim, coord, shape) \ 00400 memset((coord), 0, (ndim) * sizeof(coord[0])); \ 00401 do { 00402 00403 /* Increment to the next n-dimensional coordinate for one raw array */ 00404 #define NPY_RAW_ITER_ONE_NEXT(idim, ndim, coord, shape, data, strides) \ 00405 for ((idim) = 1; (idim) < (ndim); ++(idim)) { \ 00406 if (++(coord)[idim] == (shape)[idim]) { \ 00407 (coord)[idim] = 0; \ 00408 (data) -= ((shape)[idim] - 1) * (strides)[idim]; \ 00409 } \ 00410 else { \ 00411 (data) += (strides)[idim]; \ 00412 break; \ 00413 } \ 00414 } \ 00415 } while ((idim) < (ndim)) 00416 00417 /* Increment to the next n-dimensional coordinate for two raw arrays */ 00418 #define NPY_RAW_ITER_TWO_NEXT(idim, ndim, coord, shape, \ 00419 dataA, stridesA, dataB, stridesB) \ 00420 for ((idim) = 1; (idim) < (ndim); ++(idim)) { \ 00421 if (++(coord)[idim] == (shape)[idim]) { \ 00422 (coord)[idim] = 0; \ 00423 (dataA) -= ((shape)[idim] - 1) * (stridesA)[idim]; \ 00424 (dataB) -= ((shape)[idim] - 1) * (stridesB)[idim]; \ 00425 } \ 00426 else { \ 00427 (dataA) += (stridesA)[idim]; \ 00428 (dataB) += (stridesB)[idim]; \ 00429 break; \ 00430 } \ 00431 } \ 00432 } while ((idim) < (ndim)) 00433 00434 /* Increment to the next n-dimensional coordinate for three raw arrays */ 00435 #define NPY_RAW_ITER_THREE_NEXT(idim, ndim, coord, shape, \ 00436 dataA, stridesA, \ 00437 dataB, stridesB, \ 00438 dataC, stridesC) \ 00439 for ((idim) = 1; (idim) < (ndim); ++(idim)) { \ 00440 if (++(coord)[idim] == (shape)[idim]) { \ 00441 (coord)[idim] = 0; \ 00442 (dataA) -= ((shape)[idim] - 1) * (stridesA)[idim]; \ 00443 (dataB) -= ((shape)[idim] - 1) * (stridesB)[idim]; \ 00444 (dataC) -= ((shape)[idim] - 1) * (stridesC)[idim]; \ 00445 } \ 00446 else { \ 00447 (dataA) += (stridesA)[idim]; \ 00448 (dataB) += (stridesB)[idim]; \ 00449 (dataC) += (stridesC)[idim]; \ 00450 break; \ 00451 } \ 00452 } \ 00453 } while ((idim) < (ndim)) 00454 00455 /* Increment to the next n-dimensional coordinate for four raw arrays */ 00456 #define NPY_RAW_ITER_FOUR_NEXT(idim, ndim, coord, shape, \ 00457 dataA, stridesA, \ 00458 dataB, stridesB, \ 00459 dataC, stridesC, \ 00460 dataD, stridesD) \ 00461 for ((idim) = 1; (idim) < (ndim); ++(idim)) { \ 00462 if (++(coord)[idim] == (shape)[idim]) { \ 00463 (coord)[idim] = 0; \ 00464 (dataA) -= ((shape)[idim] - 1) * (stridesA)[idim]; \ 00465 (dataB) -= ((shape)[idim] - 1) * (stridesB)[idim]; \ 00466 (dataC) -= ((shape)[idim] - 1) * (stridesC)[idim]; \ 00467 (dataD) -= ((shape)[idim] - 1) * (stridesD)[idim]; \ 00468 } \ 00469 else { \ 00470 (dataA) += (stridesA)[idim]; \ 00471 (dataB) += (stridesB)[idim]; \ 00472 (dataC) += (stridesC)[idim]; \ 00473 (dataD) += (stridesD)[idim]; \ 00474 break; \ 00475 } \ 00476 } \ 00477 } while ((idim) < (ndim)) 00478 00479 00480 /* 00481 * TRIVIAL ITERATION 00482 * 00483 * In some cases when the iteration order isn't important, iteration over 00484 * arrays is trivial. This is the case when: 00485 * * The array has 0 or 1 dimensions. 00486 * * The array is C or Fortran contiguous. 00487 * Use of an iterator can be skipped when this occurs. These macros assist 00488 * in detecting and taking advantage of the situation. Note that it may 00489 * be worthwhile to further check if the stride is a contiguous stride 00490 * and take advantage of that. 00491 * 00492 * Here is example code for a single array: 00493 * 00494 * if (PyArray_TRIVIALLY_ITERABLE(self) { 00495 * char *data; 00496 * npy_intp count, stride; 00497 * 00498 * PyArray_PREPARE_TRIVIAL_ITERATION(self, count, data, stride); 00499 * 00500 * while (count--) { 00501 * // Use the data pointer 00502 * 00503 * data += stride; 00504 * } 00505 * } 00506 * else { 00507 * // Create iterator, etc... 00508 * } 00509 * 00510 * Here is example code for a pair of arrays: 00511 * 00512 * if (PyArray_TRIVIALLY_ITERABLE_PAIR(a1, a2) { 00513 * char *data1, *data2; 00514 * npy_intp count, stride1, stride2; 00515 * 00516 * PyArray_PREPARE_TRIVIAL_PAIR_ITERATION(a1, a2, count, 00517 * data1, data2, stride1, stride2); 00518 * 00519 * while (count--) { 00520 * // Use the data1 and data2 pointers 00521 * 00522 * data1 += stride1; 00523 * data2 += stride2; 00524 * } 00525 * } 00526 * else { 00527 * // Create iterator, etc... 00528 * } 00529 */ 00530 00531 /* 00532 * Note: Equivalently iterable macro requires one of arr1 or arr2 be 00533 * trivially iterable to be valid. 00534 */ 00535 #define PyArray_EQUIVALENTLY_ITERABLE(arr1, arr2) ( \ 00536 PyArray_NDIM(arr1) == PyArray_NDIM(arr2) && \ 00537 PyArray_CompareLists(PyArray_DIMS(arr1), \ 00538 PyArray_DIMS(arr2), \ 00539 PyArray_NDIM(arr1)) && \ 00540 (PyArray_FLAGS(arr1)&(NPY_ARRAY_C_CONTIGUOUS| \ 00541 NPY_ARRAY_F_CONTIGUOUS)) == \ 00542 (PyArray_FLAGS(arr2)&(NPY_ARRAY_C_CONTIGUOUS| \ 00543 NPY_ARRAY_F_CONTIGUOUS)) \ 00544 ) 00545 00546 #define PyArray_TRIVIALLY_ITERABLE(arr) ( \ 00547 PyArray_NDIM(arr) <= 1 || \ 00548 PyArray_CHKFLAGS(arr, NPY_ARRAY_C_CONTIGUOUS) || \ 00549 PyArray_CHKFLAGS(arr, NPY_ARRAY_F_CONTIGUOUS) \ 00550 ) 00551 #define PyArray_PREPARE_TRIVIAL_ITERATION(arr, count, data, stride) \ 00552 count = PyArray_SIZE(arr), \ 00553 data = PyArray_BYTES(arr), \ 00554 stride = ((PyArray_NDIM(arr) == 0) ? 0 : \ 00555 (PyArray_CHKFLAGS(arr, NPY_ARRAY_F_CONTIGUOUS) ? \ 00556 PyArray_STRIDE(arr, 0) : \ 00557 PyArray_STRIDE(arr, \ 00558 PyArray_NDIM(arr)-1))) 00559 00560 #define PyArray_TRIVIALLY_ITERABLE_PAIR(arr1, arr2) (\ 00561 PyArray_TRIVIALLY_ITERABLE(arr1) && \ 00562 (PyArray_NDIM(arr2) == 0 || \ 00563 PyArray_EQUIVALENTLY_ITERABLE(arr1, arr2) || \ 00564 (PyArray_NDIM(arr1) == 0 && \ 00565 PyArray_TRIVIALLY_ITERABLE(arr2) \ 00566 ) \ 00567 ) \ 00568 ) 00569 #define PyArray_PREPARE_TRIVIAL_PAIR_ITERATION(arr1, arr2, \ 00570 count, \ 00571 data1, data2, \ 00572 stride1, stride2) { \ 00573 npy_intp size1 = PyArray_SIZE(arr1); \ 00574 npy_intp size2 = PyArray_SIZE(arr2); \ 00575 count = ((size1 > size2) || size1 == 0) ? size1 : size2; \ 00576 data1 = PyArray_BYTES(arr1); \ 00577 data2 = PyArray_BYTES(arr2); \ 00578 stride1 = (size1 == 1 ? 0 : \ 00579 (PyArray_CHKFLAGS(arr1, NPY_ARRAY_F_CONTIGUOUS) ? \ 00580 PyArray_STRIDE(arr1, 0) : \ 00581 PyArray_STRIDE(arr1, \ 00582 PyArray_NDIM(arr1)-1))); \ 00583 stride2 = (size2 == 1 ? 0 : \ 00584 (PyArray_CHKFLAGS(arr2, NPY_ARRAY_F_CONTIGUOUS) ? \ 00585 PyArray_STRIDE(arr2, 0) : \ 00586 PyArray_STRIDE(arr2, \ 00587 PyArray_NDIM(arr2)-1))); \ 00588 } 00589 00590 #define PyArray_TRIVIALLY_ITERABLE_TRIPLE(arr1, arr2, arr3) (\ 00591 PyArray_TRIVIALLY_ITERABLE(arr1) && \ 00592 ((PyArray_NDIM(arr2) == 0 && \ 00593 (PyArray_NDIM(arr3) == 0 || \ 00594 PyArray_EQUIVALENTLY_ITERABLE(arr1, arr3) \ 00595 ) \ 00596 ) || \ 00597 (PyArray_EQUIVALENTLY_ITERABLE(arr1, arr2) && \ 00598 (PyArray_NDIM(arr3) == 0 || \ 00599 PyArray_EQUIVALENTLY_ITERABLE(arr1, arr3) \ 00600 ) \ 00601 ) || \ 00602 (PyArray_NDIM(arr1) == 0 && \ 00603 PyArray_TRIVIALLY_ITERABLE(arr2) && \ 00604 (PyArray_NDIM(arr3) == 0 || \ 00605 PyArray_EQUIVALENTLY_ITERABLE(arr2, arr3) \ 00606 ) \ 00607 ) \ 00608 ) \ 00609 ) 00610 00611 #define PyArray_PREPARE_TRIVIAL_TRIPLE_ITERATION(arr1, arr2, arr3, \ 00612 count, \ 00613 data1, data2, data3, \ 00614 stride1, stride2, stride3) { \ 00615 npy_intp size1 = PyArray_SIZE(arr1); \ 00616 npy_intp size2 = PyArray_SIZE(arr2); \ 00617 npy_intp size3 = PyArray_SIZE(arr3); \ 00618 count = ((size1 > size2) || size1 == 0) ? size1 : size2; \ 00619 count = ((size3 > count) || size3 == 0) ? size3 : count; \ 00620 data1 = PyArray_BYTES(arr1); \ 00621 data2 = PyArray_BYTES(arr2); \ 00622 data3 = PyArray_BYTES(arr3); \ 00623 stride1 = (size1 == 1 ? 0 : \ 00624 (PyArray_CHKFLAGS(arr1, NPY_ARRAY_F_CONTIGUOUS) ? \ 00625 PyArray_STRIDE(arr1, 0) : \ 00626 PyArray_STRIDE(arr1, \ 00627 PyArray_NDIM(arr1)-1))); \ 00628 stride2 = (size2 == 1 ? 0 : \ 00629 (PyArray_CHKFLAGS(arr2, NPY_ARRAY_F_CONTIGUOUS) ? \ 00630 PyArray_STRIDE(arr2, 0) : \ 00631 PyArray_STRIDE(arr2, \ 00632 PyArray_NDIM(arr2)-1))); \ 00633 stride3 = (size3 == 1 ? 0 : \ 00634 (PyArray_CHKFLAGS(arr3, NPY_ARRAY_F_CONTIGUOUS) ? \ 00635 PyArray_STRIDE(arr3, 0) : \ 00636 PyArray_STRIDE(arr3, \ 00637 PyArray_NDIM(arr3)-1))); \ 00638 } 00639 00640 #endif