1
/*
2
 * This file implements the API functions for NumPy's nditer that
3
 * are specialized using the templating system.
4
 *
5
 * Copyright (c) 2010-2011 by Mark Wiebe (mwwiebe@gmail.com)
6
 * The University of British Columbia
7
 *
8
 * See LICENSE.txt for the license.
9
 */
10

11
/* Indicate that this .c file is allowed to include the header */
12
#define NPY_ITERATOR_IMPLEMENTATION_CODE
13
#include "nditer_impl.h"
14

15
/* SPECIALIZED iternext functions that handle the non-buffering part */
16

17
/**begin repeat
18
 * #const_itflags = 0,
19
 *                  NPY_ITFLAG_HASINDEX,
20
 *                  NPY_ITFLAG_EXLOOP,
21
 *                  NPY_ITFLAG_RANGE,
22
 *                  NPY_ITFLAG_RANGE|NPY_ITFLAG_HASINDEX#
23
 * #tag_itflags = 0, IND, NOINN, RNG, RNGuIND#
24
 */
25
/**begin repeat1
26
 * #const_ndim = 1, 2, NPY_MAXDIMS#
27
 * #tag_ndim = 1, 2, ANY#
28
 */
29
/**begin repeat2
30
 * #const_nop = 1, 2, NPY_MAXDIMS#
31
 * #tag_nop = 1, 2, ANY#
32
 */
33

34
/* Specialized iternext (@const_itflags@,@tag_ndim@,@tag_nop@) */
35
static int
36 1
npyiter_iternext_itflags@tag_itflags@_dims@tag_ndim@_iters@tag_nop@(
37
                                                      NpyIter *iter)
38
{
39
#if !(@const_itflags@&NPY_ITFLAG_EXLOOP) || (@const_ndim@ > 1)
40 1
    const npy_uint32 itflags = @const_itflags@;
41
#  if @const_ndim@ >= NPY_MAXDIMS
42 1
    int idim, ndim = NIT_NDIM(iter);
43
#  endif
44
#  if @const_nop@ < NPY_MAXDIMS
45 1
    const int nop = @const_nop@;
46
#  else
47 1
    int nop = NIT_NOP(iter);
48
#  endif
49

50
    NpyIter_AxisData *axisdata0;
51 1
    npy_intp istrides, nstrides = NAD_NSTRIDES();
52
#endif
53
#if @const_ndim@ > 1
54
    NpyIter_AxisData *axisdata1;
55
    npy_intp sizeof_axisdata;
56
#endif
57
#if @const_ndim@ > 2
58
    NpyIter_AxisData *axisdata2;
59
#endif
60

61
#if (@const_itflags@&NPY_ITFLAG_RANGE)
62
    /* When ranged iteration is enabled, use the iterindex */
63 1
    if (++NIT_ITERINDEX(iter) >= NIT_ITEREND(iter)) {
64
        return 0;
65
    }
66
#endif
67

68
#if @const_ndim@ > 1
69 1
    sizeof_axisdata = NIT_AXISDATA_SIZEOF(itflags, ndim, nop);
70
#endif
71

72
#  if !(@const_itflags@&NPY_ITFLAG_EXLOOP) || (@const_ndim@ > 1)
73 1
    axisdata0 = NIT_AXISDATA(iter);
74
#  endif
75
#  if !(@const_itflags@&NPY_ITFLAG_EXLOOP)
76
    /* Increment index 0 */
77 1
    NAD_INDEX(axisdata0)++;
78
    /* Increment pointer 0 */
79 1
    for (istrides = 0; istrides < nstrides; ++istrides) {
80 1
        NAD_PTRS(axisdata0)[istrides] += NAD_STRIDES(axisdata0)[istrides];
81
    }
82
#  endif
83

84
#if @const_ndim@ == 1
85

86
#  if !(@const_itflags@&NPY_ITFLAG_EXLOOP)
87
    /* Finished when the index equals the shape */
88 1
    return NAD_INDEX(axisdata0) < NAD_SHAPE(axisdata0);
89
#  else
90 0
    return 0;
91
#  endif
92

93
#else
94

95
#  if !(@const_itflags@&NPY_ITFLAG_EXLOOP)
96 1
    if (NAD_INDEX(axisdata0) < NAD_SHAPE(axisdata0)) {
97
        return 1;
98
    }
99
#  endif
100

101 1
    axisdata1 = NIT_INDEX_AXISDATA(axisdata0, 1);
102
    /* Increment index 1 */
103 1
    NAD_INDEX(axisdata1)++;
104
    /* Increment pointer 1 */
105 1
    for (istrides = 0; istrides < nstrides; ++istrides) {
106 1
        NAD_PTRS(axisdata1)[istrides] += NAD_STRIDES(axisdata1)[istrides];
107
    }
108

109 1
    if (NAD_INDEX(axisdata1) < NAD_SHAPE(axisdata1)) {
110
        /* Reset the 1st index to 0 */
111 1
        NAD_INDEX(axisdata0) = 0;
112
        /* Reset the 1st pointer to the value of the 2nd */
113 1
        for (istrides = 0; istrides < nstrides; ++istrides) {
114 1
            NAD_PTRS(axisdata0)[istrides] = NAD_PTRS(axisdata1)[istrides];
115
        }
116
        return 1;
117
    }
118

119
# if @const_ndim@ == 2
120
    return 0;
121
# else
122

123 1
    axisdata2 = NIT_INDEX_AXISDATA(axisdata1, 1);
124
    /* Increment index 2 */
125 1
    NAD_INDEX(axisdata2)++;
126
    /* Increment pointer 2 */
127 1
    for (istrides = 0; istrides < nstrides; ++istrides) {
128 1
        NAD_PTRS(axisdata2)[istrides] += NAD_STRIDES(axisdata2)[istrides];
129
    }
130

131 1
    if (NAD_INDEX(axisdata2) < NAD_SHAPE(axisdata2)) {
132
        /* Reset the 1st and 2nd indices to 0 */
133 1
        NAD_INDEX(axisdata0) = 0;
134 1
        NAD_INDEX(axisdata1) = 0;
135
        /* Reset the 1st and 2nd pointers to the value of the 3nd */
136 1
        for (istrides = 0; istrides < nstrides; ++istrides) {
137 1
            NAD_PTRS(axisdata0)[istrides] = NAD_PTRS(axisdata2)[istrides];
138 1
            NAD_PTRS(axisdata1)[istrides] = NAD_PTRS(axisdata2)[istrides];
139
        }
140
        return 1;
141
    }
142

143 1
    for (idim = 3; idim < ndim; ++idim) {
144 1
        NIT_ADVANCE_AXISDATA(axisdata2, 1);
145
        /* Increment the index */
146 1
        NAD_INDEX(axisdata2)++;
147
        /* Increment the pointer */
148 1
        for (istrides = 0; istrides < nstrides; ++istrides) {
149 1
            NAD_PTRS(axisdata2)[istrides] += NAD_STRIDES(axisdata2)[istrides];
150
        }
151

152

153 1
        if (NAD_INDEX(axisdata2) < NAD_SHAPE(axisdata2)) {
154
            /* Reset the indices and pointers of all previous axisdatas */
155
            axisdata1 = axisdata2;
156
            do {
157 1
                NIT_ADVANCE_AXISDATA(axisdata1, -1);
158
                /* Reset the index to 0 */
159 1
                NAD_INDEX(axisdata1) = 0;
160
                /* Reset the pointer to the updated value */
161 1
                for (istrides = 0; istrides < nstrides; ++istrides) {
162 1
                    NAD_PTRS(axisdata1)[istrides] =
163 1
                                        NAD_PTRS(axisdata2)[istrides];
164
                }
165 1
            } while (axisdata1 != axisdata0);
166

167
            return 1;
168
        }
169
    }
170

171
    return 0;
172

173
# endif /* ndim != 2 */
174

175
#endif /* ndim != 1 */
176
}
177

178
/**end repeat2**/
179
/**end repeat1**/
180
/**end repeat**/
181

182

183
/**begin repeat
184
 * #const_nop = 1, 2, 3, 4, NPY_MAXDIMS#
185
 * #tag_nop = 1, 2, 3, 4, ANY#
186
 */
187

188
/*
189
 * Iternext function that handles the reduction buffering part.  This
190
 * is done with a double loop to avoid frequent re-buffering.
191
 */
192
static int
193 1
npyiter_buffered_reduce_iternext_iters@tag_nop@(NpyIter *iter)
194
{
195 1
    npy_uint32 itflags = NIT_ITFLAGS(iter);
196
    /*int ndim = NIT_NDIM(iter);*/
197
#if @const_nop@ >= NPY_MAXDIMS
198 1
    int nop = NIT_NOP(iter);
199
#else
200 1
    const int nop = @const_nop@;
201
#endif
202

203
    int iop;
204

205
    NpyIter_AxisData *axisdata;
206 1
    NpyIter_BufferData *bufferdata = NIT_BUFFERDATA(iter);
207
    char **ptrs;
208
    char *prev_dataptrs[NPY_MAXARGS];
209

210 1
    ptrs = NBF_PTRS(bufferdata);
211

212
    /*
213
     * If the iterator handles the inner loop, need to increment all
214
     * the indices and pointers
215
     */
216 1
    if (!(itflags&NPY_ITFLAG_EXLOOP)) {
217
        /* Increment within the buffer */
218 1
        if (++NIT_ITERINDEX(iter) < NBF_BUFITEREND(bufferdata)) {
219
            npy_intp *strides;
220

221 1
            strides = NBF_STRIDES(bufferdata);
222 1
            for (iop = 0; iop < nop; ++iop) {
223 1
                ptrs[iop] += strides[iop];
224
            }
225
            return 1;
226
        }
227
    }
228
    else {
229 1
        NIT_ITERINDEX(iter) += NBF_SIZE(bufferdata);
230
    }
231

232
    NPY_IT_DBG_PRINT1("Iterator: Finished iteration %d of outer reduce loop\n",
233
                            (int)NBF_REDUCE_POS(bufferdata));
234
    /* The outer increment for the reduce double loop */
235 1
    if (++NBF_REDUCE_POS(bufferdata) < NBF_REDUCE_OUTERSIZE(bufferdata)) {
236 1
        npy_intp *reduce_outerstrides = NBF_REDUCE_OUTERSTRIDES(bufferdata);
237 1
        char **reduce_outerptrs = NBF_REDUCE_OUTERPTRS(bufferdata);
238 1
        for (iop = 0; iop < nop; ++iop) {
239 1
            char *ptr = reduce_outerptrs[iop] + reduce_outerstrides[iop];
240 1
            ptrs[iop] = ptr;
241 1
            reduce_outerptrs[iop] = ptr;
242
        }
243 1
        NBF_BUFITEREND(bufferdata) = NIT_ITERINDEX(iter) + NBF_SIZE(bufferdata);
244 1
        return 1;
245
    }
246

247
    /* Save the previously used data pointers */
248 1
    axisdata = NIT_AXISDATA(iter);
249 1
    memcpy(prev_dataptrs, NAD_PTRS(axisdata), NPY_SIZEOF_INTP*nop);
250

251
    /* Write back to the arrays */
252 1
    if (npyiter_copy_from_buffers(iter) < 0) {
253 0
        npyiter_clear_buffers(iter);
254 0
        return 0;
255
    }
256

257
    /* Check if we're past the end */
258 1
    if (NIT_ITERINDEX(iter) >= NIT_ITEREND(iter)) {
259 1
        NBF_SIZE(bufferdata) = 0;
260 1
        return 0;
261
    }
262
    /* Increment to the next buffer */
263
    else {
264 1
        npyiter_goto_iterindex(iter, NIT_ITERINDEX(iter));
265
    }
266

267
    /* Prepare the next buffers and set iterend/size */
268 1
    if (npyiter_copy_to_buffers(iter, prev_dataptrs) < 0) {
269 1
        npyiter_clear_buffers(iter);
270 1
        return 0;
271
    }
272

273
    return 1;
274
}
275

276
/**end repeat**/
277

278
/* iternext function that handles the buffering part */
279
static int
280 1
npyiter_buffered_iternext(NpyIter *iter)
281
{
282 1
    npy_uint32 itflags = NIT_ITFLAGS(iter);
283
    /*int ndim = NIT_NDIM(iter);*/
284 1
    int nop = NIT_NOP(iter);
285

286 1
    NpyIter_BufferData *bufferdata = NIT_BUFFERDATA(iter);
287

288
    /*
289
     * If the iterator handles the inner loop, need to increment all
290
     * the indices and pointers
291
     */
292 1
    if (!(itflags&NPY_ITFLAG_EXLOOP)) {
293
        /* Increment within the buffer */
294 1
        if (++NIT_ITERINDEX(iter) < NBF_BUFITEREND(bufferdata)) {
295
            int iop;
296
            npy_intp *strides;
297
            char **ptrs;
298

299 1
            strides = NBF_STRIDES(bufferdata);
300 1
            ptrs = NBF_PTRS(bufferdata);
301 1
            for (iop = 0; iop < nop; ++iop) {
302 1
                ptrs[iop] += strides[iop];
303
            }
304
            return 1;
305
        }
306
    }
307
    else {
308 1
        NIT_ITERINDEX(iter) += NBF_SIZE(bufferdata);
309
    }
310

311
    /* Write back to the arrays */
312 1
    if (npyiter_copy_from_buffers(iter) < 0) {
313 1
        npyiter_clear_buffers(iter);
314 1
        return 0;
315
    }
316

317
    /* Check if we're past the end */
318 1
    if (NIT_ITERINDEX(iter) >= NIT_ITEREND(iter)) {
319 1
        NBF_SIZE(bufferdata) = 0;
320 1
        return 0;
321
    }
322
    /* Increment to the next buffer */
323
    else {
324 1
        npyiter_goto_iterindex(iter, NIT_ITERINDEX(iter));
325
    }
326

327
    /* Prepare the next buffers and set iterend/size */
328 1
    if (npyiter_copy_to_buffers(iter, NULL) < 0) {
329 1
        npyiter_clear_buffers(iter);
330 1
        return 0;
331
    }
332

333
    return 1;
334
}
335

336
/**end repeat2**/
337
/**end repeat1**/
338
/**end repeat**/
339

340
/* Specialization of iternext for when the iteration size is 1 */
341
static int
342 1
npyiter_iternext_sizeone(NpyIter *iter)
343
{
344 1
    return 0;
345
}
346

347
/*NUMPY_API
348
 * Compute the specialized iteration function for an iterator
349
 *
350
 * If errmsg is non-NULL, it should point to a variable which will
351
 * receive the error message, and no Python exception will be set.
352
 * This is so that the function can be called from code not holding
353
 * the GIL.
354
 */
355
NPY_NO_EXPORT NpyIter_IterNextFunc *
356 1
NpyIter_GetIterNext(NpyIter *iter, char **errmsg)
357
{
358 1
    npy_uint32 itflags = NIT_ITFLAGS(iter);
359 1
    int ndim = NIT_NDIM(iter);
360 1
    int nop = NIT_NOP(iter);
361

362 1
    if (NIT_ITERSIZE(iter) < 0) {
363 1
        if (errmsg == NULL) {
364 1
            PyErr_SetString(PyExc_ValueError, "iterator is too large");
365
        }
366
        else {
367 1
            *errmsg = "iterator is too large";
368
        }
369
        return NULL;
370
    }
371

372
    /*
373
     * When there is just one iteration and buffering is disabled
374
     * the iternext function is very simple.
375
     */
376 1
    if (itflags&NPY_ITFLAG_ONEITERATION) {
377
        return &npyiter_iternext_sizeone;
378
    }
379

380
    /*
381
     * If buffering is enabled.
382
     */
383 1
    if (itflags&NPY_ITFLAG_BUFFER) {
384 1
        if (itflags&NPY_ITFLAG_REDUCE) {
385 1
            switch (nop) {
386
                case 1:
387
                    return &npyiter_buffered_reduce_iternext_iters1;
388 1
                case 2:
389 1
                    return &npyiter_buffered_reduce_iternext_iters2;
390 1
                case 3:
391 1
                    return &npyiter_buffered_reduce_iternext_iters3;
392 1
                case 4:
393 1
                    return &npyiter_buffered_reduce_iternext_iters4;
394 1
                default:
395 1
                    return &npyiter_buffered_reduce_iternext_itersANY;
396
            }
397
        }
398
        else {
399
            return &npyiter_buffered_iternext;
400
        }
401
    }
402

403
    /*
404
     * Ignore all the flags that don't affect the iterator memory
405
     * layout or the iternext function.  Currently only HASINDEX,
406
     * EXLOOP, and RANGE affect them here.
407
     */
408 1
    itflags &= (NPY_ITFLAG_HASINDEX|NPY_ITFLAG_EXLOOP|NPY_ITFLAG_RANGE);
409

410
    /* Switch statements let the compiler optimize this most effectively */
411 1
    switch (itflags) {
412
    /*
413
     * The combinations HASINDEX|EXLOOP and RANGE|EXLOOP are excluded
414
     * by the New functions
415
     */
416
/**begin repeat
417
 * #const_itflags = 0,
418
 *                  NPY_ITFLAG_HASINDEX,
419
 *                  NPY_ITFLAG_EXLOOP,
420
 *                  NPY_ITFLAG_RANGE,
421
 *                  NPY_ITFLAG_RANGE|NPY_ITFLAG_HASINDEX#
422
 * #tag_itflags = 0, IND, NOINN, RNG, RNGuIND#
423
 */
424 1
        case @const_itflags@:
425 1
            switch (ndim) {
426
/**begin repeat1
427
 * #const_ndim = 1, 2#
428
 * #tag_ndim = 1, 2#
429
 */
430 1
                case @const_ndim@:
431 1
                    switch (nop) {
432
/**begin repeat2
433
 * #const_nop = 1, 2#
434
 * #tag_nop = 1, 2#
435
 */
436 1
                        case @const_nop@:
437 1
                            return &npyiter_iternext_itflags@tag_itflags@_dims@tag_ndim@_iters@tag_nop@;
438
/**end repeat2**/
439
                        /* Not specialized on nop */
440 1
                        default:
441 1
                            return &npyiter_iternext_itflags@tag_itflags@_dims@tag_ndim@_itersANY;
442
                    }
443
/**end repeat1**/
444
                /* Not specialized on ndim */
445 1
                default:
446 1
                    switch (nop) {
447
/**begin repeat1
448
 * #const_nop = 1, 2#
449
 * #tag_nop = 1, 2#
450
 */
451 1
                        case @const_nop@:
452 1
                            return &npyiter_iternext_itflags@tag_itflags@_dimsANY_iters@tag_nop@;
453
/**end repeat1**/
454
                        /* Not specialized on nop */
455 1
                        default:
456 1
                            return &npyiter_iternext_itflags@tag_itflags@_dimsANY_itersANY;
457
                    }
458
            }
459
/**end repeat**/
460
    }
461
    /* The switch above should have caught all the possibilities. */
462 0
    if (errmsg == NULL) {
463 0
        PyErr_Format(PyExc_ValueError,
464
                "GetIterNext internal iterator error - unexpected "
465
                "itflags/ndim/nop combination (%04x/%d/%d)",
466
                (int)itflags, (int)ndim, (int)nop);
467
    }
468
    else {
469 0
        *errmsg = "GetIterNext internal iterator error - unexpected "
470
                  "itflags/ndim/nop combination";
471
    }
472
    return NULL;
473
}
474

475

476
/* SPECIALIZED getindex functions */
477

478
/**begin repeat
479
 * #const_itflags = 0,
480
 *    NPY_ITFLAG_HASINDEX,
481
 *    NPY_ITFLAG_IDENTPERM,
482
 *    NPY_ITFLAG_HASINDEX|NPY_ITFLAG_IDENTPERM,
483
 *    NPY_ITFLAG_NEGPERM,
484
 *    NPY_ITFLAG_HASINDEX|NPY_ITFLAG_NEGPERM,
485
 *    NPY_ITFLAG_BUFFER,
486
 *    NPY_ITFLAG_HASINDEX|NPY_ITFLAG_BUFFER,
487
 *    NPY_ITFLAG_IDENTPERM|NPY_ITFLAG_BUFFER,
488
 *    NPY_ITFLAG_HASINDEX|NPY_ITFLAG_IDENTPERM|NPY_ITFLAG_BUFFER,
489
 *    NPY_ITFLAG_NEGPERM|NPY_ITFLAG_BUFFER,
490
 *    NPY_ITFLAG_HASINDEX|NPY_ITFLAG_NEGPERM|NPY_ITFLAG_BUFFER#
491
 * #tag_itflags = 0, IND, IDP, INDuIDP, NEGP, INDuNEGP,
492
 *                BUF, INDuBUF, IDPuBUF, INDuIDPuBUF, NEGPuBUF, INDuNEGPuBUF#
493
 */
494
static void
495 1
npyiter_get_multi_index_itflags@tag_itflags@(
496
                        NpyIter *iter, npy_intp *out_multi_index)
497
{
498 1
    const npy_uint32 itflags = @const_itflags@;
499 1
    int idim, ndim = NIT_NDIM(iter);
500 1
    int nop = NIT_NOP(iter);
501

502
    npy_intp sizeof_axisdata;
503
    NpyIter_AxisData *axisdata;
504
#if !((@const_itflags@)&NPY_ITFLAG_IDENTPERM)
505 1
    npy_int8 *perm = NIT_PERM(iter);
506
#endif
507

508 1
    axisdata = NIT_AXISDATA(iter);
509 1
    sizeof_axisdata = NIT_AXISDATA_SIZEOF(itflags, ndim, nop);
510
#if ((@const_itflags@)&NPY_ITFLAG_IDENTPERM)
511 1
    out_multi_index += ndim-1;
512 1
    for(idim = 0; idim < ndim; ++idim, --out_multi_index,
513 1
                                    NIT_ADVANCE_AXISDATA(axisdata, 1)) {
514 1
        *out_multi_index = NAD_INDEX(axisdata);
515
    }
516
#elif !((@const_itflags@)&NPY_ITFLAG_NEGPERM)
517 1
    for(idim = 0; idim < ndim; ++idim, NIT_ADVANCE_AXISDATA(axisdata, 1)) {
518 1
        npy_int8 p = perm[idim];
519 1
        out_multi_index[ndim-p-1] = NAD_INDEX(axisdata);
520
    }
521
#else
522 1
    for(idim = 0; idim < ndim; ++idim, NIT_ADVANCE_AXISDATA(axisdata, 1)) {
523 1
        npy_int8 p = perm[idim];
524 1
        if (p < 0) {
525
            /* If the perm entry is negative, reverse the index */
526 1
            out_multi_index[ndim+p] = NAD_SHAPE(axisdata) - NAD_INDEX(axisdata) - 1;
527
        }
528
        else {
529 1
            out_multi_index[ndim-p-1] = NAD_INDEX(axisdata);
530
        }
531
    }
532
#endif /* not ident perm */
533 1
}
534
/**end repeat**/
535

536
/*NUMPY_API
537
 * Compute a specialized get_multi_index function for the iterator
538
 *
539
 * If errmsg is non-NULL, it should point to a variable which will
540
 * receive the error message, and no Python exception will be set.
541
 * This is so that the function can be called from code not holding
542
 * the GIL.
543
 */
544
NPY_NO_EXPORT NpyIter_GetMultiIndexFunc *
545 1
NpyIter_GetGetMultiIndex(NpyIter *iter, char **errmsg)
546
{
547 1
    npy_uint32 itflags = NIT_ITFLAGS(iter);
548 1
    int ndim = NIT_NDIM(iter);
549 1
    int nop = NIT_NOP(iter);
550

551
    /* These flags must be correct */
552 1
    if ((itflags&(NPY_ITFLAG_HASMULTIINDEX|NPY_ITFLAG_DELAYBUF)) !=
553
            NPY_ITFLAG_HASMULTIINDEX) {
554 0
        if (!(itflags&NPY_ITFLAG_HASMULTIINDEX)) {
555 0
            if (errmsg == NULL) {
556 0
                PyErr_SetString(PyExc_ValueError,
557
                        "Cannot retrieve a GetMultiIndex function for an "
558
                        "iterator that doesn't track a multi-index.");
559
            }
560
            else {
561 0
                *errmsg = "Cannot retrieve a GetMultiIndex function for an "
562
                          "iterator that doesn't track a multi-index.";
563
            }
564
            return NULL;
565
        }
566
        else {
567 0
            if (errmsg == NULL) {
568 0
                PyErr_SetString(PyExc_ValueError,
569
                        "Cannot retrieve a GetMultiIndex function for an "
570
                        "iterator that used DELAY_BUFALLOC before a Reset call");
571
            }
572
            else {
573 0
                *errmsg = "Cannot retrieve a GetMultiIndex function for an "
574
                          "iterator that used DELAY_BUFALLOC before a "
575
                          "Reset call";
576
            }
577
            return NULL;
578
        }
579
    }
580

581
    /*
582
     * Only these flags affect the iterator memory layout or
583
     * the get_multi_index behavior. IDENTPERM and NEGPERM are mutually
584
     * exclusive, so that reduces the number of cases slightly.
585
     */
586 1
    itflags &= (NPY_ITFLAG_HASINDEX |
587
                NPY_ITFLAG_IDENTPERM |
588
                NPY_ITFLAG_NEGPERM |
589
                NPY_ITFLAG_BUFFER);
590

591 1
    switch (itflags) {
592
/**begin repeat
593
 * #const_itflags = 0,
594
 *    NPY_ITFLAG_HASINDEX,
595
 *    NPY_ITFLAG_IDENTPERM,
596
 *    NPY_ITFLAG_HASINDEX|NPY_ITFLAG_IDENTPERM,
597
 *    NPY_ITFLAG_NEGPERM,
598
 *    NPY_ITFLAG_HASINDEX|NPY_ITFLAG_NEGPERM,
599
 *    NPY_ITFLAG_BUFFER,
600
 *    NPY_ITFLAG_HASINDEX|NPY_ITFLAG_BUFFER,
601
 *    NPY_ITFLAG_IDENTPERM|NPY_ITFLAG_BUFFER,
602
 *    NPY_ITFLAG_HASINDEX|NPY_ITFLAG_IDENTPERM|NPY_ITFLAG_BUFFER,
603
 *    NPY_ITFLAG_NEGPERM|NPY_ITFLAG_BUFFER,
604
 *    NPY_ITFLAG_HASINDEX|NPY_ITFLAG_NEGPERM|NPY_ITFLAG_BUFFER#
605
 * #tag_itflags = 0, IND, IDP, INDuIDP, NEGP, INDuNEGP,
606
 *                BUF, INDuBUF, IDPuBUF, INDuIDPuBUF, NEGPuBUF, INDuNEGPuBUF#
607
 */
608 1
        case @const_itflags@:
609 1
            return npyiter_get_multi_index_itflags@tag_itflags@;
610
/**end repeat**/
611
    }
612
    /* The switch above should have caught all the possibilities. */
613 0
    if (errmsg == NULL) {
614 0
        PyErr_Format(PyExc_ValueError,
615
                "GetGetMultiIndex internal iterator error - unexpected "
616
                "itflags/ndim/nop combination (%04x/%d/%d)",
617
                (int)itflags, (int)ndim, (int)nop);
618
    }
619
    else {
620 0
        *errmsg = "GetGetMultiIndex internal iterator error - unexpected "
621
                  "itflags/ndim/nop combination";
622
    }
623
    return NULL;
624

625
}
626

627
#undef NPY_ITERATOR_IMPLEMENTATION_CODE

Read our documentation on viewing source code .

Loading