@@ -3263,17 +3263,61 @@ name_filter(PyObject *Py_UNUSED(m), PyObject *n) {
32633263 return n ;
32643264}
32653265
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+
32663311// Represent a 1D array as a 2D array with length as rows of a single-column array.
32673312// https://stackoverflow.com/questions/56182259/how-does-one-acces-numpy-multidimensionnal-array-in-c-extensions
32683313static PyObject *
32693314shape_filter (PyObject * Py_UNUSED (m ), PyObject * a ) {
32703315 AK_CHECK_NUMPY_ARRAY_1D_2D (a );
32713316 PyArrayObject * array = (PyArrayObject * )a ;
3272-
3273- npy_intp size0 = PyArray_DIM (array , 0 );
3317+ npy_intp rows = PyArray_DIM (array , 0 );
32743318 // 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 );
32773321}
32783322
32793323// 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) {
42404284 return NULL ;
42414285 }
42424286 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
42444288}
42454289
42464290//------------------------------------------------------------------------------
@@ -4671,6 +4715,8 @@ typedef struct BIIterContiguousObject {
46714715 bool reduce ; // optionally reduce slices to integers
46724716} BIIterContiguousObject ;
46734717
4718+
4719+ // Create a new contiguous slice iterator. Return NULL on error. Steals a reference to PyObject* iter.
46744720static PyObject *
46754721BIIterContiguous_new (BlockIndexObject * bi ,
46764722 bool reversed ,
@@ -4684,9 +4730,7 @@ BIIterContiguous_new(BlockIndexObject *bi,
46844730 Py_INCREF ((PyObject * )bi );
46854731 bii -> bi = bi ;
46864732
4687- Py_INCREF (iter );
4688- bii -> iter = iter ;
4689-
4733+ bii -> iter = iter ; // steals ref
46904734 bii -> reversed = reversed ;
46914735
46924736 bii -> last_block = -1 ;
@@ -4746,9 +4790,8 @@ BIIterContiguous_reversed(BIIterContiguousObject *self)
47464790 }
47474791 PyObject * biiter = BIIterContiguous_new (self -> bi ,
47484792 reversed ,
4749- self -> iter ,
4793+ iter , // steals ref
47504794 self -> reduce );
4751- Py_DECREF (iter );
47524795 return biiter ;
47534796}
47544797
@@ -4788,7 +4831,10 @@ BIIterContiguous_iternext(BIIterContiguousObject *self)
47884831 }
47894832 // no more pairs, return previous slice_start, flag for end on next call
47904833 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
47924838 self -> last_block ,
47934839 AK_build_slice_inclusive (slice_start ,
47944840 self -> last_column ,
@@ -4813,7 +4859,7 @@ BIIterContiguous_iternext(BIIterContiguousObject *self)
48134859 }
48144860 self -> next_block = block ;
48154861 self -> next_column = column ;
4816- return Py_BuildValue ( "nN" , // N steals ref
4862+ return AK_build_pair_ssize_t_slice ( // steals ref
48174863 self -> last_block ,
48184864 AK_build_slice_inclusive (slice_start ,
48194865 self -> last_column ,
@@ -5211,7 +5257,7 @@ BlockIndex_to_list(BlockIndexObject *self, PyObject *Py_UNUSED(unused)) {
52115257 BlockIndexRecord * bir = self -> bir ;
52125258
52135259 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 );
52155261 if (item == NULL ) {
52165262 Py_DECREF (list );
52175263 return NULL ;
@@ -5248,17 +5294,14 @@ BlockIndex_getstate(BlockIndexObject *self) {
52485294 return NULL ;
52495295 }
52505296 PyObject * dt = self -> dtype == NULL ? Py_None : (PyObject * ) self -> dtype ;
5251-
52525297 // 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
52545299 self -> block_count ,
52555300 self -> row_count ,
52565301 self -> bir_count ,
52575302 self -> bir_capacity ,
5258- bi ,
5303+ bi , // stolen new ref
52595304 dt ); // increfs passed object
5260-
5261- Py_DECREF (bi );
52625305 return state ;
52635306}
52645307
@@ -5283,7 +5326,7 @@ BlockIndex_shape_getter(BlockIndexObject *self, void* Py_UNUSED(closure))
52835326{
52845327 if (self -> shape == NULL || self -> shape_recache ) {
52855328 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 );
52875330 }
52885331 // shape is not null and shape_recache is false
52895332 Py_INCREF (self -> shape ); // for caller
@@ -5447,14 +5490,11 @@ BlockIndex_iter_contiguous(BlockIndexObject *self, PyObject *args, PyObject *kwa
54475490 )) {
54485491 return NULL ;
54495492 }
5450-
5451- // might need to store enum type for branching
54525493 PyObject * iter = BIIterSelector_new (self , selector , 0 , BIIS_UNKNOWN , ascending );
54535494 if (iter == NULL ) {
54545495 return NULL ; // exception set
54555496 }
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
54585498 return biiter ;
54595499}
54605500
0 commit comments