Data Structures |
struct | NpyIter_InternalOnly |
struct | NpyIter_BD |
struct | NpyIter_AD |
Defines |
#define | PY_SSIZE_T_CLEAN |
#define | _MULTIARRAYMODULE |
#define | NPY_IT_CONSTRUCTION_TIMING 0 |
#define | NPY_IT_TIME_POINT(var) |
#define | NPY_IT_DBG_TRACING 0 |
#define | NPY_IT_DBG_PRINT(s) |
#define | NPY_IT_DBG_PRINT1(s, p1) |
#define | NPY_IT_DBG_PRINT2(s, p1, p2) |
#define | NPY_IT_DBG_PRINT3(s, p1, p2, p3) |
#define | NPY_INTP_ALIGNED(size) ((size + 0x7)&(-0x8)) |
#define | NPY_ITFLAG_IDENTPERM 0x0001 |
#define | NPY_ITFLAG_NEGPERM 0x0002 |
#define | NPY_ITFLAG_HASINDEX 0x0004 |
#define | NPY_ITFLAG_HASMULTIINDEX 0x0008 |
#define | NPY_ITFLAG_FORCEDORDER 0x0010 |
#define | NPY_ITFLAG_EXLOOP 0x0020 |
#define | NPY_ITFLAG_RANGE 0x0040 |
#define | NPY_ITFLAG_BUFFER 0x0080 |
#define | NPY_ITFLAG_GROWINNER 0x0100 |
#define | NPY_ITFLAG_ONEITERATION 0x0200 |
#define | NPY_ITFLAG_DELAYBUF 0x0400 |
#define | NPY_ITFLAG_NEEDSAPI 0x0800 |
#define | NPY_ITFLAG_REDUCE 0x1000 |
#define | NPY_ITFLAG_REUSE_REDUCE_LOOPS 0x2000 |
#define | NPY_OP_ITFLAG_WRITE 0x01 |
#define | NPY_OP_ITFLAG_READ 0x02 |
#define | NPY_OP_ITFLAG_CAST 0x04 |
#define | NPY_OP_ITFLAG_BUFNEVER 0x08 |
#define | NPY_OP_ITFLAG_ALIGNED 0x10 |
#define | NPY_OP_ITFLAG_REDUCE 0x20 |
#define | NIT_PERM_SIZEOF(itflags, ndim, nop) NPY_INTP_ALIGNED(NPY_MAXDIMS) |
#define | NIT_DTYPES_SIZEOF(itflags, ndim, nop) ((NPY_SIZEOF_INTP)*(nop)) |
#define | NIT_RESETDATAPTR_SIZEOF(itflags, ndim, nop) ((NPY_SIZEOF_INTP)*(nop+1)) |
#define | NIT_BASEOFFSETS_SIZEOF(itflags, ndim, nop) ((NPY_SIZEOF_INTP)*(nop+1)) |
#define | NIT_OPERANDS_SIZEOF(itflags, ndim, nop) ((NPY_SIZEOF_INTP)*(nop)) |
#define | NIT_OPITFLAGS_SIZEOF(itflags, ndim, nop) (NPY_INTP_ALIGNED(nop)) |
#define | NIT_BUFFERDATA_SIZEOF(itflags, ndim, nop) ((itflags&NPY_ITFLAG_BUFFER) ? ((NPY_SIZEOF_INTP)*(6 + 9*nop)) : 0) |
#define | NIT_PERM_OFFSET() (0) |
#define | NIT_DTYPES_OFFSET(itflags, ndim, nop) |
#define | NIT_RESETDATAPTR_OFFSET(itflags, ndim, nop) |
#define | NIT_BASEOFFSETS_OFFSET(itflags, ndim, nop) |
#define | NIT_OPERANDS_OFFSET(itflags, ndim, nop) |
#define | NIT_OPITFLAGS_OFFSET(itflags, ndim, nop) |
#define | NIT_BUFFERDATA_OFFSET(itflags, ndim, nop) |
#define | NIT_AXISDATA_OFFSET(itflags, ndim, nop) |
#define | NIT_ITFLAGS(iter) ((iter)->itflags) |
#define | NIT_NDIM(iter) ((iter)->ndim) |
#define | NIT_NOP(iter) ((iter)->nop) |
#define | NIT_ITERSIZE(iter) (iter->itersize) |
#define | NIT_ITERSTART(iter) (iter->iterstart) |
#define | NIT_ITEREND(iter) (iter->iterend) |
#define | NIT_ITERINDEX(iter) (iter->iterindex) |
#define | NIT_PERM(iter) |
#define | NIT_DTYPES(iter) |
#define | NIT_RESETDATAPTR(iter) |
#define | NIT_BASEOFFSETS(iter) |
#define | NIT_OPERANDS(iter) |
#define | NIT_OPITFLAGS(iter) |
#define | NIT_BUFFERDATA(iter) |
#define | NIT_AXISDATA(iter) |
#define | NBF_BUFFERSIZE(bufferdata) ((bufferdata)->buffersize) |
#define | NBF_SIZE(bufferdata) ((bufferdata)->size) |
#define | NBF_BUFITEREND(bufferdata) ((bufferdata)->bufiterend) |
#define | NBF_REDUCE_POS(bufferdata) ((bufferdata)->reduce_pos) |
#define | NBF_REDUCE_OUTERSIZE(bufferdata) ((bufferdata)->reduce_outersize) |
#define | NBF_REDUCE_OUTERDIM(bufferdata) ((bufferdata)->reduce_outerdim) |
#define | NBF_STRIDES(bufferdata) |
#define | NBF_PTRS(bufferdata) |
#define | NBF_REDUCE_OUTERSTRIDES(bufferdata) |
#define | NBF_REDUCE_OUTERPTRS(bufferdata) |
#define | NBF_READTRANSFERFN(bufferdata) |
#define | NBF_READTRANSFERDATA(bufferdata) |
#define | NBF_WRITETRANSFERFN(bufferdata) |
#define | NBF_WRITETRANSFERDATA(bufferdata) |
#define | NBF_BUFFERS(bufferdata) |
#define | NAD_SHAPE(axisdata) ((axisdata)->shape) |
#define | NAD_INDEX(axisdata) ((axisdata)->index) |
#define | NAD_STRIDES(axisdata) |
#define | NAD_PTRS(axisdata) |
#define | NAD_NSTRIDES() ((nop) + ((itflags&NPY_ITFLAG_HASINDEX) ? 1 : 0)) |
#define | NIT_AXISDATA_SIZEOF(itflags, ndim, nop) |
#define | NIT_INDEX_AXISDATA(axisdata, index) |
#define | NIT_ADVANCE_AXISDATA(axisdata, count) axisdata = NIT_INDEX_AXISDATA(axisdata, count) |
#define | NIT_SIZEOF_ITERATOR(itflags, ndim, nop) |
Typedefs |
typedef struct NpyIter_AD | NpyIter_AxisData |
typedef struct NpyIter_BD | NpyIter_BufferData |
Functions |
static int | npyiter_check_global_flags (npy_uint32 flags, npy_uint32 *itflags) |
static int | npyiter_check_op_axes (int nop, int oa_ndim, int **op_axes, npy_intp *itershape) |
static int | npyiter_calculate_ndim (int nop, PyArrayObject **op_in, int oa_ndim) |
static int | npyiter_check_per_op_flags (npy_uint32 flags, char *op_itflags) |
static int | npyiter_prepare_one_operand (PyArrayObject **op, char **op_dataptr, PyArray_Descr *op_request_dtype, PyArray_Descr **op_dtype, npy_uint32 flags, npy_uint32 op_flags, char *op_itflags) |
static int | npyiter_prepare_operands (int nop, PyArrayObject **op_in, PyArrayObject **op, char **op_dataptr, PyArray_Descr **op_request_dtypes, PyArray_Descr **op_dtype, npy_uint32 flags, npy_uint32 *op_flags, char *op_itflags) |
static int | npyiter_check_casting (int nop, PyArrayObject **op, PyArray_Descr **op_dtype, NPY_CASTING casting, char *op_itflags) |
static int | npyiter_fill_axisdata (NpyIter *iter, npy_uint32 flags, char *op_itflags, char **op_dataptr, npy_uint32 *op_flags, int **op_axes, npy_intp *itershape, int output_scalars) |
static void | npyiter_replace_axisdata (NpyIter *iter, int iop, PyArrayObject *op, int op_ndim, char *op_dataptr, int *op_axes) |
static void | npyiter_compute_index_strides (NpyIter *iter, npy_uint32 flags) |
static void | npyiter_apply_forced_iteration_order (NpyIter *iter, NPY_ORDER order) |
static void | npyiter_flip_negative_strides (NpyIter *iter) |
static void | npyiter_reverse_axis_ordering (NpyIter *iter) |
static void | npyiter_find_best_axis_ordering (NpyIter *iter) |
static void | npyiter_coalesce_axes (NpyIter *iter) |
static PyArray_Descr * | npyiter_get_common_dtype (int nop, PyArrayObject **op, char *op_itflags, PyArray_Descr **op_dtype, PyArray_Descr **op_request_dtypes, int only_inputs, int output_scalars) |
static PyArrayObject * | npyiter_new_temp_array (NpyIter *iter, PyTypeObject *subtype, npy_uint32 flags, char *op_itflags, int op_ndim, npy_intp *shape, PyArray_Descr *op_dtype, int *op_axes) |
static int | npyiter_allocate_arrays (NpyIter *iter, npy_uint32 flags, PyArray_Descr **op_dtype, PyTypeObject *subtype, npy_uint32 *op_flags, char *op_itflags, int **op_axes, int output_scalars) |
static void | npyiter_get_priority_subtype (int nop, PyArrayObject **op, char *op_itflags, double *subtype_priority, PyTypeObject **subtype) |
static int | npyiter_allocate_transfer_functions (NpyIter *iter) |
static int | npyiter_allocate_buffers (NpyIter *iter, char **errmsg) |
static void | npyiter_goto_iterindex (NpyIter *iter, npy_intp iterindex) |
static void | npyiter_copy_from_buffers (NpyIter *iter) |
static void | npyiter_copy_to_buffers (NpyIter *iter, char **prev_dataptrs) |
static npy_intp | npyiter_checkreducesize (NpyIter *iter, npy_intp count, npy_intp *reduce_innersize, npy_intp *reduce_outerdim) |
NPY_NO_EXPORT NpyIter * | NpyIter_AdvancedNew (int nop, PyArrayObject **op_in, npy_uint32 flags, NPY_ORDER order, NPY_CASTING casting, npy_uint32 *op_flags, PyArray_Descr **op_request_dtypes, int oa_ndim, int **op_axes, npy_intp *itershape, npy_intp buffersize) |
NPY_NO_EXPORT NpyIter * | NpyIter_MultiNew (int nop, PyArrayObject **op_in, npy_uint32 flags, NPY_ORDER order, NPY_CASTING casting, npy_uint32 *op_flags, PyArray_Descr **op_request_dtypes) |
NPY_NO_EXPORT NpyIter * | NpyIter_New (PyArrayObject *op, npy_uint32 flags, NPY_ORDER order, NPY_CASTING casting, PyArray_Descr *dtype) |
NPY_NO_EXPORT NpyIter * | NpyIter_Copy (NpyIter *iter) |
NPY_NO_EXPORT int | NpyIter_Deallocate (NpyIter *iter) |
NPY_NO_EXPORT int | NpyIter_RemoveAxis (NpyIter *iter, int axis) |
NPY_NO_EXPORT int | NpyIter_RemoveMultiIndex (NpyIter *iter) |
NPY_NO_EXPORT int | NpyIter_EnableExternalLoop (NpyIter *iter) |
NPY_NO_EXPORT int | NpyIter_Reset (NpyIter *iter, char **errmsg) |
NPY_NO_EXPORT int | NpyIter_ResetBasePointers (NpyIter *iter, char **baseptrs, char **errmsg) |
NPY_NO_EXPORT int | NpyIter_ResetToIterIndexRange (NpyIter *iter, npy_intp istart, npy_intp iend, char **errmsg) |
NPY_NO_EXPORT int | NpyIter_GotoMultiIndex (NpyIter *iter, npy_intp *multi_index) |
NPY_NO_EXPORT int | NpyIter_GotoIndex (NpyIter *iter, npy_intp flat_index) |
NPY_NO_EXPORT int | NpyIter_GotoIterIndex (NpyIter *iter, npy_intp iterindex) |
NPY_NO_EXPORT npy_intp | NpyIter_GetIterIndex (NpyIter *iter) |
static int
npyiter_iternext_itflags
tag_itflags _dims tag_ndim
_iters | tag_nop (NpyIter *iter) |
static int | npyiter_buffered_iternext (NpyIter *iter) |
static int | npyiter_iternext_sizeone (NpyIter *iter) |
NPY_NO_EXPORT
NpyIter_IterNextFunc * | NpyIter_GetIterNext (NpyIter *iter, char **errmsg) |
static void
npyiter_get_multi_index_itflags | tag_itflags (NpyIter *iter, npy_intp *out_multi_index) |
NPY_NO_EXPORT
NpyIter_GetMultiIndexFunc * | NpyIter_GetGetMultiIndex (NpyIter *iter, char **errmsg) |
NPY_NO_EXPORT npy_bool | NpyIter_HasDelayedBufAlloc (NpyIter *iter) |
NPY_NO_EXPORT npy_bool | NpyIter_HasExternalLoop (NpyIter *iter) |
NPY_NO_EXPORT npy_bool | NpyIter_HasMultiIndex (NpyIter *iter) |
NPY_NO_EXPORT npy_bool | NpyIter_HasIndex (NpyIter *iter) |
NPY_NO_EXPORT npy_bool | NpyIter_RequiresBuffering (NpyIter *iter) |
NPY_NO_EXPORT npy_bool | NpyIter_IterationNeedsAPI (NpyIter *iter) |
NPY_NO_EXPORT int | NpyIter_GetNDim (NpyIter *iter) |
NPY_NO_EXPORT int | NpyIter_GetNOp (NpyIter *iter) |
NPY_NO_EXPORT npy_intp | NpyIter_GetIterSize (NpyIter *iter) |
NPY_NO_EXPORT npy_bool | NpyIter_IsBuffered (NpyIter *iter) |
NPY_NO_EXPORT npy_bool | NpyIter_IsGrowInner (NpyIter *iter) |
NPY_NO_EXPORT npy_intp | NpyIter_GetBufferSize (NpyIter *iter) |
NPY_NO_EXPORT void | NpyIter_GetIterIndexRange (NpyIter *iter, npy_intp *istart, npy_intp *iend) |
NPY_NO_EXPORT int | NpyIter_GetShape (NpyIter *iter, npy_intp *outshape) |
NPY_NO_EXPORT int | NpyIter_CreateCompatibleStrides (NpyIter *iter, npy_intp itemsize, npy_intp *outstrides) |
NPY_NO_EXPORT char ** | NpyIter_GetDataPtrArray (NpyIter *iter) |
NPY_NO_EXPORT char ** | NpyIter_GetInitialDataPtrArray (NpyIter *iter) |
NPY_NO_EXPORT PyArray_Descr ** | NpyIter_GetDescrArray (NpyIter *iter) |
NPY_NO_EXPORT PyArrayObject ** | NpyIter_GetOperandArray (NpyIter *iter) |
NPY_NO_EXPORT PyArrayObject * | NpyIter_GetIterView (NpyIter *iter, npy_intp i) |
NPY_NO_EXPORT npy_intp * | NpyIter_GetIndexPtr (NpyIter *iter) |
NPY_NO_EXPORT void | NpyIter_GetReadFlags (NpyIter *iter, char *outreadflags) |
NPY_NO_EXPORT void | NpyIter_GetWriteFlags (NpyIter *iter, char *outwriteflags) |
NPY_NO_EXPORT npy_intp * | NpyIter_GetInnerStrideArray (NpyIter *iter) |
NPY_NO_EXPORT npy_intp * | NpyIter_GetAxisStrideArray (NpyIter *iter, int axis) |
NPY_NO_EXPORT void | NpyIter_GetInnerFixedStrideArray (NpyIter *iter, npy_intp *out_strides) |
NPY_NO_EXPORT npy_intp * | NpyIter_GetInnerLoopSizePtr (NpyIter *iter) |
static const char * | npyiter_casting_to_string (NPY_CASTING casting) |
static PyObject * | npyiter_shape_string (npy_intp n, npy_intp *vals, char *ending) |
static npy_intp | intp_abs (npy_intp x) |
NPY_NO_EXPORT void | NpyIter_DebugPrint (NpyIter *iter) |
NPY_NO_EXPORT NpyIter* NpyIter_AdvancedNew |
( |
int |
nop, |
|
|
PyArrayObject ** |
op_in, |
|
|
npy_uint32 |
flags, |
|
|
NPY_ORDER |
order, |
|
|
NPY_CASTING |
casting, |
|
|
npy_uint32 * |
op_flags, |
|
|
PyArray_Descr ** |
op_request_dtypes, |
|
|
int |
oa_ndim, |
|
|
int ** |
op_axes, |
|
|
npy_intp * |
itershape, |
|
|
npy_intp |
buffersize |
|
) |
| |
- Allocate a new iterator for multiple array objects, and advanced
- options for controlling the broadcasting, shape, and buffer size.
The iterator being constructed
Per-operand values
The subtype for automatically allocated outputs
Error check 'oa_ndim' and 'op_axes', which must be used together
Check the global iterator flags
Calculate how many dimensions the iterator should have
If 'ndim' is zero, any outputs should be scalars
Allocate memory for the iterator
Fill in the basic data
Prepare all the operands
Set resetindex to zero as well (it's just after the resetdataptr)
Initialize buffer data (must set the buffers and transferdata to NULL before we might deallocate the iterator).
Fill in the AXISDATA arrays and set the ITERSIZE field
If buffering is enabled and no buffersize was given, use a default chosen to be big enough to get some amortization benefits, but small enough to be cache-friendly.
No point in a buffer bigger than the iteration size
If an index was requested, compute the strides for it. Note that we must do this before changing the order of the axes
Initialize the perm to the identity
If an iteration order is being forced, apply it.
Set some flags for allocated outputs
Flag this so later we can avoid flipping axes
If a subtype may be used, indicate so
If the data type wasn't provided, will need to calculate it.
If the ordering was not forced, reorder the axes and flip negative strides to find the best one.
If there's an output being allocated, we must not negate any strides.
If an automatically allocated output didn't have a specified dtype, we need to figure it out now, before allocating the outputs.
Replace all the data types
Replace the NULL data types
All of the data types have been settled, so it's time to check that data type conversions are following the casting rules.
At this point, the iteration order has been finalized. so any allocation of ops that were NULL, or any temporary copying due to casting/byte order/alignment can be done now using a memory layout matching the iterator.
Finally, if a multi-index wasn't requested, it may be possible to coalesce some axes together.
The operation may have changed the layout, so we have to get the internal pointers again.
Now that the axes are finished, check whether we can apply the single iteration optimization to the iternext function.
If REFS_OK was specified, check whether there are any reference arrays and flag it if so.
Iteration needs API access
If buffering is set without delayed allocation
Make the data pointers NULL
Allocate the buffers
Prepare the next buffers and set iterend/size
static int npyiter_allocate_arrays |
( |
NpyIter * |
iter, |
|
|
npy_uint32 |
flags, |
|
|
PyArray_Descr ** |
op_dtype, |
|
|
PyTypeObject * |
subtype, |
|
|
npy_uint32 * |
op_flags, |
|
|
char * |
op_itflags, |
|
|
int ** |
op_axes, |
|
|
int |
output_scalars |
|
) |
| [static] |
NULL means an output the iterator should allocate
Check whether the subtype was disabled
Allocate the output array
Now we need to replace the pointers and strides with values from the new array.
New arrays are aligned and need no cast
If casting is required, the operand is read-only, and it's an array scalar, make a copy whether or not the copy flag is enabled.
Now we need to replace the pointers and strides with values from the temporary array.
New arrays are aligned need no cast, and in the case of scalars, always have stride 0 so never need buffering
If casting is required and permitted
Allocate the temporary array, if possible
If the data will be read, copy it into temp
If the data will be written to, set UPDATEIFCOPY
Now we need to replace the pointers and strides with values from the temporary array.
The temporary copy is aligned and needs no cast
Buffering must be enabled for casting/conversion if copy wasn't specified.
If the operand is aligned, any buffering can use aligned optimizations.
Here we can finally check for contiguous iteration
If no alignment, byte swap, or casting is needed, and the inner stride of this operand works for the whole array, we can set NPY_OP_ITFLAG_BUFNEVER.
Find stride of the first non-empty shape
Check that everything could have coalesced together
If N times the inner stride doesn't equal this stride, the multi-dimensionality is needed.
If we looped all the way to the end, one stride works. Set that stride, because it may not belong to the first dimension.
This checks how much space can be buffered without encountering the same value twice, or for operands whose innermost stride is zero, without encountering a different value. By reducing the buffered amount to this size, reductions can be safely buffered.
Reductions are buffered with two levels of looping, to avoid frequent copying to the buffers. The return value is the over-all buffer size, and when the flag NPY_ITFLAG_REDUCE is set, reduce_innersize receives the size of the inner of the two levels of looping.
The value placed in reduce_outerdim is the index into the AXISDATA for where the second level of the double loop begins.
The return value is always a multiple of the value placed in reduce_innersize.
Default to no outer axis
If there's only one dimension, no need to calculate anything
Indicate which REDUCE operands have stride 0 in the inner loop
Go forward through axisdata, calculating the space available
If a reduce stride switched from zero to non-zero, or vice versa, that's the point where the data will stop being the same element or will repeat, and if the buffer starts with an all zero multi-index up to this point, gives us the reduce_innersize.
If we already found more elements than count, or the starting coordinate wasn't zero, the two-level looping is unnecessary/can't be done, so return.
If we broke out of the loop early, we found reduce_innersize
If there was any non-zero coordinate, can't do the double loop
In this case, we can't reuse the reduce loops
In this case, we can reuse the reduce loops
Continue through the rest of the dimensions. If there are two separated reduction axes, we may have to cut the buffer short again.
Indicate which REDUCE operands have stride 0 at the current level
If a reduce stride switched from zero to non-zero, or vice versa, that's the point where the data will stop being the same element or will repeat, and if the buffer starts with an all zero multi-index up to this point, gives us the reduce_innersize.
This terminates the outer level of our double loop.
static void npyiter_copy_to_buffers |
( |
NpyIter * |
iter, |
|
|
char ** |
prev_dataptrs |
|
) |
| [static] |
This gets called after the iterator has been positioned to a multi-index for the start of a buffer. It decides which operands need a buffer, and copies the data into the buffers.
Have to get this flag before npyiter_checkreducesize sets it for the next iteration.
Calculate the size if using any buffers
If last time around, the reduce loop structure was full, we reuse it
If there are any reduction operands, we may have to make the size smaller so we don't copy the same value into a buffer twice, as the buffering does not have a mechanism to combine values itself.
Calculate the maximum size if using a single stride and no buffers
If the buffer is write-only, these two are NULL, and the buffer pointers will be set up but the read copy won't be done
Never need to buffer this operand
Should not adjust the stride - ad_strides[iop] could be zero, but strides[iop] was initialized to the first non-trivial stride.
Never need to buffer this operand
Should not adjust the stride - ad_strides[iop] could be zero, but strides[iop] was initialized to the first non-trivial stride.
Just a copy
No copyswap or cast was requested, so all we're doing is copying the data to fill the buffer and produce a single stride. If the underlying data already does that, no need to copy it.
If some other op is reduced, we have a double reduce loop
In this case, the buffer is being used
Just a copy, but with a reduction
It's all in one stride in the inner loop dimension
It's all in one stride in the reduce outer loop
Outer reduce loop advances by one item
In this case, the buffer is being used
Both outer and inner reduce loops have stride 0
Outer reduce loop advances by one item
It's all in one stride in the reduce outer loop
Outer reduce loop advances by one item
In this case, the buffer is being used
Reduction in outer reduce loop
Advance to next items in outer reduce loop
In this case, the buffer is being used
The buffer is being used with reduction
Both outer and inner reduce loops have stride 0
Outer reduce loop advances by one item
Reduction in outer reduce loop
Advance to next items in outer reduce loop
If this operand is being reduced in the inner loop, set its buffering stride to zero, and just copy one element.
When we're reducing a single element, and it's still the same element, don't overwrite it even when reuse reduce loops is unset. This preserves the precision of the intermediate calculation.
If the whole buffered loop structure remains the same, and the source pointer for this data didn't change, we don't have to copy the data again.
If the data type requires zero-inititialization
Can't skip the transfer in this case
If the data type requires zero-inititialization
If buffering wasn't needed, we can grow the inner loop to as large as possible.
TODO: Could grow REDUCE loop too with some more logic above.
static PyArrayObject * npyiter_new_temp_array |
( |
NpyIter * |
iter, |
|
|
PyTypeObject * |
subtype, |
|
|
npy_uint32 |
flags, |
|
|
char * |
op_itflags, |
|
|
int |
op_ndim, |
|
|
npy_intp * |
shape, |
|
|
PyArray_Descr * |
op_dtype, |
|
|
int * |
op_axes |
|
) |
| [static] |
Allocates a temporary array which can be used to replace op in the iteration. Its dtype will be op_dtype.
The result array has a memory ordering which matches the iterator, which may or may not match that of op. The parameter 'shape' may be NULL, in which case it is filled in from the iterator's shape.
This function must be called before any axes are coalesced.
If it's a scalar, don't need to check the axes
Double-check that the subtype didn't mess with the dimensions
Initialize the strides to invalid values
Apply the perm to get the original axis
If deleting this axis produces a reduction, but reduction wasn't enabled, throw an error
Indicate that a reduction is occurring
Apply the perm to get the original axis
If custom axes were specified, some dimensions may not have been used. Add the REDUCE itflag if this creates a reduction situation.
Ensure there are no dimension gaps in op_axes, and find op_ndim
If there's a gap in the array's dimensions, it's an error. For example, op_axes of [0,2] for the automatically allocated output.
Fill in the missing strides in C order
Copy the missing strides, and multiply the existing strides by the calculated factor. This way, the missing strides are tighter together in memory, which is good for nested loops.
If shape was NULL, set it to the shape we calculated
Allocate the temporary array
If there are any reversed axes, create a view that reverses them
Make sure all the flags are good
Double-check that the subtype didn't mess with the dimensions
static int npyiter_prepare_one_operand |
( |
PyArrayObject ** |
op, |
|
|
char ** |
op_dataptr, |
|
|
PyArray_Descr * |
op_request_dtype, |
|
|
PyArray_Descr ** |
op_dtype, |
|
|
npy_uint32 |
flags, |
|
|
npy_uint32 |
op_flags, |
|
|
char * |
op_itflags |
|
) |
| [static] |
Prepares a a constructor operand. Assumes a reference to 'op' is owned, and that 'op' may be replaced. Fills in 'op_dtype' and 'ndim'.
Returns 1 on success, 0 on failure.
NULL operands must be automatically allocated outputs
ALLOCATE should be enabled
Writing should be enabled
Reading should be disabled if buffering is enabled without also enabling NPY_ITER_DELAY_BUFALLOC. In all other cases, the caller may initialize the allocated operand to a value before beginning iteration.
If a requested dtype was provided, use it, otherwise NULL
PyArray_DESCR does not give us a reference
If references weren't specifically allowed, make sure there are no references in the inputs or requested dtypes.
Checking whether casts are valid is done later, once the final data types have been selected. For now, just store the requested type.
We just have a borrowed reference to op_request_dtype
If it's a data type without a size, set the size
Store the requested dtype
Check if the operand is in the byte order requested
Check byte order
Replace with a new descr which is in native byte order
Indicate that byte order or alignment needs fixing
Check if the operand is aligned
Check alignment
The check for NPY_ITER_CONTIG can only be done later, once the final iteration order is settled.
Referenced by NpyIter_GetIterView().