@@ -3263,17 +3263,61 @@ name_filter(PyObject *Py_UNUSED(m), PyObject *n) {
3263
3263
return n ;
3264
3264
}
3265
3265
3266
+ // Returns NULL on error. Returns a new reference.
3267
+ static inline PyObject *
3268
+ AK_build_pair_ssize_t (Py_ssize_t a , Py_ssize_t b )
3269
+ {
3270
+ PyObject * t = PyTuple_New (2 );
3271
+ if (t == NULL ) {
3272
+ return NULL ;
3273
+ }
3274
+ PyObject * py_a = PyLong_FromSsize_t (a );
3275
+ if (py_a == NULL ) {
3276
+ Py_DECREF (t );
3277
+ return NULL ;
3278
+ }
3279
+ PyObject * py_b = PyLong_FromSsize_t (b );
3280
+ if (py_b == NULL ) {
3281
+ Py_DECREF (t );
3282
+ Py_DECREF (py_a );
3283
+ return NULL ;
3284
+ }
3285
+ PyTuple_SET_ITEM (t , 0 , py_a );
3286
+ PyTuple_SET_ITEM (t , 1 , py_b );
3287
+ return t ;
3288
+ }
3289
+
3290
+ // Returns NULL on error. Returns a new reference. Note that a reference is stolen from the PyObject argument.
3291
+ static inline PyObject *
3292
+ AK_build_pair_ssize_t_slice (Py_ssize_t a , PyObject * py_b )
3293
+ {
3294
+ if (py_b == NULL ) { // construction failed
3295
+ return NULL ;
3296
+ }
3297
+ PyObject * t = PyTuple_New (2 );
3298
+ if (t == NULL ) {
3299
+ return NULL ;
3300
+ }
3301
+ PyObject * py_a = PyLong_FromSsize_t (a );
3302
+ if (py_a == NULL ) {
3303
+ Py_DECREF (t );
3304
+ return NULL ;
3305
+ }
3306
+ PyTuple_SET_ITEM (t , 0 , py_a );
3307
+ PyTuple_SET_ITEM (t , 1 , py_b );
3308
+ return t ;
3309
+ }
3310
+
3266
3311
// Represent a 1D array as a 2D array with length as rows of a single-column array.
3267
3312
// https://stackoverflow.com/questions/56182259/how-does-one-acces-numpy-multidimensionnal-array-in-c-extensions
3268
3313
static PyObject *
3269
3314
shape_filter (PyObject * Py_UNUSED (m ), PyObject * a ) {
3270
3315
AK_CHECK_NUMPY_ARRAY_1D_2D (a );
3271
3316
PyArrayObject * array = (PyArrayObject * )a ;
3272
-
3273
- npy_intp size0 = PyArray_DIM (array , 0 );
3317
+ npy_intp rows = PyArray_DIM (array , 0 );
3274
3318
// If 1D array, set size for axis 1 at 1, else use 2D array to get the size of axis 1
3275
- npy_intp size1 = PyArray_NDIM (array ) == 1 ? 1 : PyArray_DIM (array , 1 );
3276
- return Py_BuildValue ( "nn" , size0 , size1 );
3319
+ npy_intp cols = PyArray_NDIM (array ) == 1 ? 1 : PyArray_DIM (array , 1 );
3320
+ return AK_build_pair_ssize_t ( rows , cols );
3277
3321
}
3278
3322
3279
3323
// Reshape if necessary a flat ndim 1 array into a 2D array with one columns and rows of length.
@@ -4240,7 +4284,7 @@ AK_BI_item(BlockIndexObject* self, Py_ssize_t i) {
4240
4284
return NULL ;
4241
4285
}
4242
4286
BlockIndexRecord * biri = & self -> bir [i ];
4243
- return Py_BuildValue ( "nn" , biri -> block , biri -> column ); // maybe NULL
4287
+ return AK_build_pair_ssize_t ( biri -> block , biri -> column ); // may be NULL
4244
4288
}
4245
4289
4246
4290
//------------------------------------------------------------------------------
@@ -4671,6 +4715,8 @@ typedef struct BIIterContiguousObject {
4671
4715
bool reduce ; // optionally reduce slices to integers
4672
4716
} BIIterContiguousObject ;
4673
4717
4718
+
4719
+ // Create a new contiguous slice iterator. Return NULL on error. Steals a reference to PyObject* iter.
4674
4720
static PyObject *
4675
4721
BIIterContiguous_new (BlockIndexObject * bi ,
4676
4722
bool reversed ,
@@ -4684,9 +4730,7 @@ BIIterContiguous_new(BlockIndexObject *bi,
4684
4730
Py_INCREF ((PyObject * )bi );
4685
4731
bii -> bi = bi ;
4686
4732
4687
- Py_INCREF (iter );
4688
- bii -> iter = iter ;
4689
-
4733
+ bii -> iter = iter ; // steals ref
4690
4734
bii -> reversed = reversed ;
4691
4735
4692
4736
bii -> last_block = -1 ;
@@ -4746,9 +4790,8 @@ BIIterContiguous_reversed(BIIterContiguousObject *self)
4746
4790
}
4747
4791
PyObject * biiter = BIIterContiguous_new (self -> bi ,
4748
4792
reversed ,
4749
- self -> iter ,
4793
+ iter , // steals ref
4750
4794
self -> reduce );
4751
- Py_DECREF (iter );
4752
4795
return biiter ;
4753
4796
}
4754
4797
@@ -4788,7 +4831,10 @@ BIIterContiguous_iternext(BIIterContiguousObject *self)
4788
4831
}
4789
4832
// no more pairs, return previous slice_start, flag for end on next call
4790
4833
self -> next_block = -2 ;
4791
- return Py_BuildValue ("nN" , // N steals ref
4834
+ if (self -> last_block == -1 ) { // iter produced no values, terminate
4835
+ break ;
4836
+ }
4837
+ return AK_build_pair_ssize_t_slice ( // steals ref
4792
4838
self -> last_block ,
4793
4839
AK_build_slice_inclusive (slice_start ,
4794
4840
self -> last_column ,
@@ -4813,7 +4859,7 @@ BIIterContiguous_iternext(BIIterContiguousObject *self)
4813
4859
}
4814
4860
self -> next_block = block ;
4815
4861
self -> next_column = column ;
4816
- return Py_BuildValue ( "nN" , // N steals ref
4862
+ return AK_build_pair_ssize_t_slice ( // steals ref
4817
4863
self -> last_block ,
4818
4864
AK_build_slice_inclusive (slice_start ,
4819
4865
self -> last_column ,
@@ -5211,7 +5257,7 @@ BlockIndex_to_list(BlockIndexObject *self, PyObject *Py_UNUSED(unused)) {
5211
5257
BlockIndexRecord * bir = self -> bir ;
5212
5258
5213
5259
for (Py_ssize_t i = 0 ; i < self -> bir_count ; i ++ ) {
5214
- PyObject * item = Py_BuildValue ( "nn" , bir [i ].block , bir [i ].column );
5260
+ PyObject * item = AK_build_pair_ssize_t ( bir [i ].block , bir [i ].column );
5215
5261
if (item == NULL ) {
5216
5262
Py_DECREF (list );
5217
5263
return NULL ;
@@ -5248,17 +5294,14 @@ BlockIndex_getstate(BlockIndexObject *self) {
5248
5294
return NULL ;
5249
5295
}
5250
5296
PyObject * dt = self -> dtype == NULL ? Py_None : (PyObject * ) self -> dtype ;
5251
-
5252
5297
// state might be NULL on failure; assume exception set
5253
- PyObject * state = Py_BuildValue ("nnnnOO" ,
5298
+ PyObject * state = Py_BuildValue ("nnnnNO" , // use N to steal ref of bytes
5254
5299
self -> block_count ,
5255
5300
self -> row_count ,
5256
5301
self -> bir_count ,
5257
5302
self -> bir_capacity ,
5258
- bi ,
5303
+ bi , // stolen new ref
5259
5304
dt ); // increfs passed object
5260
-
5261
- Py_DECREF (bi );
5262
5305
return state ;
5263
5306
}
5264
5307
@@ -5283,7 +5326,7 @@ BlockIndex_shape_getter(BlockIndexObject *self, void* Py_UNUSED(closure))
5283
5326
{
5284
5327
if (self -> shape == NULL || self -> shape_recache ) {
5285
5328
Py_XDECREF (self -> shape ); // get rid of old if it exists
5286
- self -> shape = Py_BuildValue ( "nn" , self -> row_count , self -> bir_count ); // new ref
5329
+ self -> shape = AK_build_pair_ssize_t ( self -> row_count , self -> bir_count );
5287
5330
}
5288
5331
// shape is not null and shape_recache is false
5289
5332
Py_INCREF (self -> shape ); // for caller
@@ -5447,14 +5490,11 @@ BlockIndex_iter_contiguous(BlockIndexObject *self, PyObject *args, PyObject *kwa
5447
5490
)) {
5448
5491
return NULL ;
5449
5492
}
5450
-
5451
- // might need to store enum type for branching
5452
5493
PyObject * iter = BIIterSelector_new (self , selector , 0 , BIIS_UNKNOWN , ascending );
5453
5494
if (iter == NULL ) {
5454
5495
return NULL ; // exception set
5455
5496
}
5456
- PyObject * biiter = BIIterContiguous_new (self , 0 , iter , reduce ); // might be NULL, will incref iter
5457
- Py_DECREF (iter );
5497
+ PyObject * biiter = BIIterContiguous_new (self , 0 , iter , reduce ); // might be NULL, steals iter ref
5458
5498
return biiter ;
5459
5499
}
5460
5500
0 commit comments