@@ -4401,7 +4401,6 @@ BIIterSlice_new(BlockIndexObject *bi, PyObject* slice, int8_t reversed) {
44014401 if (!bii ) {
44024402 return NULL ;
44034403 }
4404-
44054404 Py_INCREF (bi );
44064405 bii -> bi = bi ;
44074406 // we store the slice in case we need to delegate to a different iterator
@@ -4491,6 +4490,135 @@ static PyTypeObject BIIterSliceType = {
44914490};
44924491
44934492
4493+ //------------------------------------------------------------------------------
4494+ // BI Iterator Boolean array selection
4495+ static PyTypeObject BIIterBooleanType ;
4496+
4497+ typedef struct BIIterBooleanObject {
4498+ PyObject_VAR_HEAD
4499+ BlockIndexObject * bi ;
4500+ int8_t reversed ;
4501+ PyObject * array ;
4502+ Py_ssize_t pos ; // current index, mutated in-place
4503+ Py_ssize_t len ;
4504+ } BIIterBooleanObject ;
4505+
4506+ static PyObject *
4507+ BIIterBoolean_new (BlockIndexObject * bi , PyObject * array , int8_t reversed ) {
4508+ BIIterBooleanObject * bii = PyObject_New (BIIterBooleanObject , & BIIterBooleanType );
4509+ if (!bii ) {
4510+ return NULL ;
4511+ }
4512+ Py_INCREF (bi );
4513+ bii -> bi = bi ;
4514+ // we store the slice in case we need to delegate to a different iterator
4515+ Py_INCREF (array );
4516+ bii -> array = array ;
4517+
4518+ if (PyArray_Check (array )) {
4519+ PyArrayObject * a = (PyArrayObject * )array ;
4520+ if (PyArray_NDIM (a ) != 1 ) {
4521+ PyErr_SetString (PyExc_TypeError , "Arrays must be 1-dimensional" );
4522+ goto error ;
4523+ }
4524+ if (PyArray_TYPE (a ) != NPY_BOOL ) {
4525+ PyErr_SetString (PyExc_TypeError , "Arrays must be Boolean" );
4526+ goto error ;
4527+ }
4528+ if ((bii -> len = PyArray_SIZE (a )) != bi -> bir_count ) {
4529+ PyErr_SetString (PyExc_TypeError , "Arrays must match length" );
4530+ goto error ;
4531+ }
4532+ }
4533+ else {
4534+ PyErr_SetString (PyExc_TypeError , "Input type not supported" );
4535+ goto error ;
4536+ }
4537+
4538+ // always initialize bii->pos to a valid index
4539+ if ((bii -> reversed = reversed )) {
4540+ bii -> pos = bii -> len - 1 ;
4541+ }
4542+ else {
4543+ bii -> pos = 0 ;
4544+ }
4545+ return (PyObject * )bii ;
4546+ error :
4547+ Py_DECREF (bii -> bi );
4548+ Py_DECREF (bii -> array );
4549+ return NULL ;
4550+ }
4551+
4552+ static void
4553+ BIIterBoolean_dealloc (BIIterBooleanObject * self ) {
4554+ Py_DECREF (self -> bi );
4555+ Py_DECREF (self -> array );
4556+ Py_TYPE (self )-> tp_free ((PyObject * )self );
4557+ }
4558+
4559+ static BIIterBooleanObject *
4560+ BIIterBoolean_iter (BIIterBooleanObject * self ) {
4561+ Py_INCREF (self );
4562+ return self ;
4563+ }
4564+
4565+ static PyObject *
4566+ BIIterBoolean_iternext (BIIterBooleanObject * self ) {
4567+ npy_bool v = 0 ;
4568+ Py_ssize_t i = -1 ;
4569+ PyArrayObject * a = (PyArrayObject * ) self -> array ;
4570+
4571+ if (!self -> reversed ) {
4572+ while (self -> pos < self -> len ) {
4573+ v = * (npy_bool * )PyArray_GETPTR1 (a , self -> pos );
4574+ if (v ) {
4575+ i = self -> pos ;
4576+ self -> pos ++ ;
4577+ break ;
4578+ }
4579+ self -> pos ++ ;
4580+ }
4581+ }
4582+ else { // reversed
4583+ while (self -> pos >= 0 ) {
4584+ v = * (npy_bool * )PyArray_GETPTR1 (a , self -> pos );
4585+ if (v ) {
4586+ i = self -> pos ;
4587+ self -> pos -- ;
4588+ break ;
4589+ }
4590+ self -> pos -- ;
4591+ }
4592+ }
4593+ if (i != -1 ) {
4594+ return AK_BI_item (self -> bi , i ); // return new ref
4595+ }
4596+ return NULL ; // no True remain
4597+ }
4598+
4599+ static PyObject *
4600+ BIIterBoolean_reversed (BIIterBooleanObject * self ) {
4601+ return BIIterBoolean_new (self -> bi , self -> array , !self -> reversed );
4602+ }
4603+
4604+ // NOTE: no length hint given as we would have to traverse whole array and count True... not sure it is worht it.
4605+ static PyMethodDef BIiterBoolean_methods [] = {
4606+ // {"__length_hint__", (PyCFunction)BIIterBoolean_length_hint, METH_NOARGS, NULL},
4607+ {"__reversed__" , (PyCFunction )BIIterBoolean_reversed , METH_NOARGS , NULL },
4608+ {NULL },
4609+ };
4610+
4611+ static PyTypeObject BIIterBooleanType = {
4612+ PyVarObject_HEAD_INIT (NULL , 0 )
4613+ .tp_basicsize = sizeof (BIIterBooleanObject ),
4614+ .tp_dealloc = (destructor ) BIIterBoolean_dealloc ,
4615+ .tp_iter = (getiterfunc ) BIIterBoolean_iter ,
4616+ .tp_iternext = (iternextfunc ) BIIterBoolean_iternext ,
4617+ .tp_methods = BIiterBoolean_methods ,
4618+ .tp_name = "arraykit.BlockIndexIteratorBoolean" ,
4619+ };
4620+
4621+
44944622//------------------------------------------------------------------------------
44954623
44964624// Returns 0 on succes, -1 on error.
@@ -5254,6 +5382,7 @@ PyInit__arraykit(void)
52545382 PyType_Ready (& BIIterType ) ||
52555383 PyType_Ready (& BIIterSeqType ) ||
52565384 PyType_Ready (& BIIterSliceType ) ||
5385+ PyType_Ready (& BIIterBooleanType ) ||
52575386 PyType_Ready (& ArrayGOType ) ||
52585387 PyModule_AddObject (m , "BlockIndex" , (PyObject * ) & BlockIndexType ) ||
52595388 PyModule_AddObject (m , "ArrayGO" , (PyObject * ) & ArrayGOType ) ||
0 commit comments