@@ -3282,14 +3282,15 @@ AK_build_pair_ssize_t(Py_ssize_t a, Py_ssize_t b)
3282
3282
Py_DECREF (py_a );
3283
3283
return NULL ;
3284
3284
}
3285
+ // steals refs
3285
3286
PyTuple_SET_ITEM (t , 0 , py_a );
3286
3287
PyTuple_SET_ITEM (t , 1 , py_b );
3287
3288
return t ;
3288
3289
}
3289
3290
3290
3291
// Returns NULL on error. Returns a new reference. Note that a reference is stolen from the PyObject argument.
3291
3292
static inline PyObject *
3292
- AK_build_pair_ssize_t_slice (Py_ssize_t a , PyObject * py_b )
3293
+ AK_build_pair_ssize_t_pyo (Py_ssize_t a , PyObject * py_b )
3293
3294
{
3294
3295
if (py_b == NULL ) { // construction failed
3295
3296
return NULL ;
@@ -3303,6 +3304,7 @@ AK_build_pair_ssize_t_slice(Py_ssize_t a, PyObject* py_b)
3303
3304
Py_DECREF (t );
3304
3305
return NULL ;
3305
3306
}
3307
+ // steals refs
3306
3308
PyTuple_SET_ITEM (t , 0 , py_a );
3307
3309
PyTuple_SET_ITEM (t , 1 , py_b );
3308
3310
return t ;
@@ -4264,7 +4266,7 @@ typedef struct BlockIndexRecord {
4264
4266
} BlockIndexRecord ;
4265
4267
4266
4268
typedef struct BlockIndexObject {
4267
- PyObject_VAR_HEAD
4269
+ PyObject_HEAD
4268
4270
Py_ssize_t block_count ;
4269
4271
Py_ssize_t row_count ;
4270
4272
Py_ssize_t bir_count ;
@@ -4292,7 +4294,7 @@ AK_BI_item(BlockIndexObject* self, Py_ssize_t i) {
4292
4294
static PyTypeObject BIIterType ;
4293
4295
4294
4296
typedef struct BIIterObject {
4295
- PyObject_VAR_HEAD
4297
+ PyObject_HEAD
4296
4298
BlockIndexObject * bi ;
4297
4299
bool reversed ;
4298
4300
Py_ssize_t pos ; // current index state, mutated in-place
@@ -4393,7 +4395,7 @@ BIIterSelector_new(BlockIndexObject *bi,
4393
4395
);
4394
4396
4395
4397
typedef struct BIIterSeqObject {
4396
- PyObject_VAR_HEAD
4398
+ PyObject_HEAD
4397
4399
BlockIndexObject * bi ;
4398
4400
bool reversed ;
4399
4401
PyObject * selector ;
@@ -4484,7 +4486,6 @@ BIIterSeq_iternext_index(BIIterSeqObject *self)
4484
4486
return t ;
4485
4487
}
4486
4488
4487
-
4488
4489
static PyObject *
4489
4490
BIIterSeq_iternext (BIIterSeqObject * self )
4490
4491
{
@@ -4498,7 +4499,7 @@ BIIterSeq_iternext(BIIterSeqObject *self)
4498
4499
static PyObject *
4499
4500
BIIterSeq_reversed (BIIterSeqObject * self )
4500
4501
{
4501
- return BIIterSelector_new (self -> bi , self -> selector , !self -> reversed , BIIS_SEQ , 0 );
4502
+ return BIIterSelector_new (self -> bi , self -> selector , !self -> reversed , BIIS_SEQ , false );
4502
4503
}
4503
4504
4504
4505
static PyObject *
@@ -4529,7 +4530,7 @@ static PyTypeObject BIIterSeqType = {
4529
4530
// BI Iterator slice selection
4530
4531
4531
4532
typedef struct BIIterSliceObject {
4532
- PyObject_VAR_HEAD
4533
+ PyObject_HEAD
4533
4534
BlockIndexObject * bi ;
4534
4535
bool reversed ;
4535
4536
PyObject * selector ; // slice
@@ -4580,7 +4581,7 @@ BIIterSlice_iternext(BIIterSliceObject *self) {
4580
4581
static PyObject *
4581
4582
BIIterSlice_reversed (BIIterSliceObject * self )
4582
4583
{
4583
- return BIIterSelector_new (self -> bi , self -> selector , !self -> reversed , BIIS_SLICE , 0 );
4584
+ return BIIterSelector_new (self -> bi , self -> selector , !self -> reversed , BIIS_SLICE , false );
4584
4585
}
4585
4586
4586
4587
static PyObject *
@@ -4611,7 +4612,7 @@ static PyTypeObject BIIterSliceType = {
4611
4612
// BI Iterator Boolean array selection
4612
4613
4613
4614
typedef struct BIIterBooleanObject {
4614
- PyObject_VAR_HEAD
4615
+ PyObject_HEAD
4615
4616
BlockIndexObject * bi ;
4616
4617
bool reversed ;
4617
4618
PyObject * selector ;
@@ -4701,10 +4702,11 @@ static PyTypeObject BIIterBoolType = {
4701
4702
4702
4703
//------------------------------------------------------------------------------
4703
4704
// BI Iterator Contigous
4705
+
4704
4706
static PyTypeObject BIIterContiguousType ;
4705
4707
4706
4708
typedef struct BIIterContiguousObject {
4707
- PyObject_VAR_HEAD
4709
+ PyObject_HEAD
4708
4710
BlockIndexObject * bi ;
4709
4711
PyObject * iter ; // own reference to core iterator
4710
4712
bool reversed ;
@@ -4834,7 +4836,7 @@ BIIterContiguous_iternext(BIIterContiguousObject *self)
4834
4836
if (self -> last_block == -1 ) { // iter produced no values, terminate
4835
4837
break ;
4836
4838
}
4837
- return AK_build_pair_ssize_t_slice ( // steals ref
4839
+ return AK_build_pair_ssize_t_pyo ( // steals ref
4838
4840
self -> last_block ,
4839
4841
AK_build_slice_inclusive (slice_start ,
4840
4842
self -> last_column ,
@@ -4859,7 +4861,7 @@ BIIterContiguous_iternext(BIIterContiguousObject *self)
4859
4861
}
4860
4862
self -> next_block = block ;
4861
4863
self -> next_column = column ;
4862
- return AK_build_pair_ssize_t_slice ( // steals ref
4864
+ return AK_build_pair_ssize_t_pyo ( // steals ref
4863
4865
self -> last_block ,
4864
4866
AK_build_slice_inclusive (slice_start ,
4865
4867
self -> last_column ,
@@ -4885,6 +4887,105 @@ static PyTypeObject BIIterContiguousType = {
4885
4887
.tp_name = "arraykit.BlockIndexContiguousIterator" ,
4886
4888
};
4887
4889
4890
+ //------------------------------------------------------------------------------
4891
+ // BI Iterator Block Slice
4892
+
4893
+ static PyTypeObject BIIterBlockType ;
4894
+
4895
+ typedef struct BIIterBlockObject {
4896
+ PyObject_HEAD
4897
+ BlockIndexObject * bi ;
4898
+ bool reversed ;
4899
+ Py_ssize_t pos ; // current index state, mutated in-place
4900
+ PyObject * null_slice ;
4901
+ } BIIterBlockObject ;
4902
+
4903
+ static PyObject *
4904
+ BIIterBlock_new (BlockIndexObject * bi , bool reversed ) {
4905
+ BIIterBlockObject * bii = PyObject_New (BIIterBlockObject , & BIIterBlockType );
4906
+ if (!bii ) {
4907
+ return NULL ;
4908
+ }
4909
+ Py_INCREF ((PyObject * )bi );
4910
+ bii -> bi = bi ;
4911
+ bii -> reversed = reversed ;
4912
+ bii -> pos = 0 ;
4913
+
4914
+ // create a new ref of the null slice
4915
+ PyObject * ns = AK_build_slice (-1 , -1 , 1 ); // get all null; new ref
4916
+ if (ns == NULL ) {
4917
+ return NULL ;
4918
+ }
4919
+ bii -> null_slice = ns ;
4920
+ return (PyObject * )bii ;
4921
+ }
4922
+
4923
+ static void
4924
+ BIIterBlock_dealloc (BIIterBlockObject * self ) {
4925
+ Py_DECREF ((PyObject * )self -> bi );
4926
+ Py_DECREF (self -> null_slice );
4927
+ PyObject_Del ((PyObject * )self );
4928
+ }
4929
+
4930
+ static PyObject *
4931
+ BIIterBlock_iter (BIIterBlockObject * self ) {
4932
+ Py_INCREF (self );
4933
+ return (PyObject * )self ;
4934
+ }
4935
+
4936
+ static PyObject *
4937
+ BIIterBlock_iternext (BIIterBlockObject * self ) {
4938
+ Py_ssize_t i ;
4939
+ if (self -> reversed ) {
4940
+ i = self -> bi -> block_count - ++ self -> pos ;
4941
+ if (i < 0 ) {
4942
+ return NULL ;
4943
+ }
4944
+ }
4945
+ else {
4946
+ i = self -> pos ++ ;
4947
+ }
4948
+ if (self -> bi -> block_count <= i ) {
4949
+ return NULL ;
4950
+ }
4951
+ // AK_build_pair_ssize_t_pyo steals the reference to the object; so incref here
4952
+ Py_INCREF (self -> null_slice );
4953
+ PyObject * t = AK_build_pair_ssize_t_pyo (i , self -> null_slice ); // return new ref
4954
+ if (t == NULL ) {
4955
+ // if tuple creation failed need to undo incref
4956
+ Py_DECREF (self -> null_slice );
4957
+ }
4958
+ return t ;
4959
+ }
4960
+
4961
+ static PyObject *
4962
+ BIIterBlock_reversed (BIIterBlockObject * self ) {
4963
+ return BIIterBlock_new (self -> bi , !self -> reversed );
4964
+ }
4965
+
4966
+ static PyObject *
4967
+ BIIterBlock_length_hint (BIIterBlockObject * self ) {
4968
+ // this works for reversed as we use self->pos to subtract from length
4969
+ Py_ssize_t len = Py_MAX (0 , self -> bi -> block_count - self -> pos );
4970
+ return PyLong_FromSsize_t (len );
4971
+ }
4972
+
4973
+ static PyMethodDef BIIterBlock_methods [] = {
4974
+ {"__length_hint__" , (PyCFunction )BIIterBlock_length_hint , METH_NOARGS , NULL },
4975
+ {"__reversed__" , (PyCFunction )BIIterBlock_reversed , METH_NOARGS , NULL },
4976
+ {NULL },
4977
+ };
4978
+
4979
+ static PyTypeObject BIIterBlockType = {
4980
+ PyVarObject_HEAD_INIT (NULL , 0 )
4981
+ .tp_basicsize = sizeof (BIIterBlockObject ),
4982
+ .tp_dealloc = (destructor ) BIIterBlock_dealloc ,
4983
+ .tp_iter = (getiterfunc ) BIIterBlock_iter ,
4984
+ .tp_iternext = (iternextfunc ) BIIterBlock_iternext ,
4985
+ .tp_methods = BIIterBlock_methods ,
4986
+ .tp_name = "arraykit.BlockIndexBlockIterator" ,
4987
+ };
4988
+
4888
4989
//------------------------------------------------------------------------------
4889
4990
4890
4991
// NOTE: this constructor returns one of three different PyObject types. We do this to consolidate error reporting and type checks.
@@ -5203,6 +5304,7 @@ BlockIndex_register(BlockIndexObject *self, PyObject *value) {
5203
5304
Py_ssize_t alignment = PyArray_DIM (a , 0 );
5204
5305
if (self -> row_count == -1 ) {
5205
5306
self -> row_count = alignment ;
5307
+ self -> shape_recache = true; // setting rows, must recache shape
5206
5308
}
5207
5309
else if (self -> row_count != alignment ) {
5208
5310
PyErr_Format (ErrorInitTypeBlocks ,
@@ -5321,12 +5423,17 @@ BlockIndex_setstate(BlockIndexObject *self, PyObject *state)
5321
5423
//------------------------------------------------------------------------------
5322
5424
// getters
5323
5425
5426
+ // Never expose a negative row value to the caller
5427
+ #define AK_BI_ROWS (rows ) ((rows) < 0 ? 0 : (rows))
5428
+
5324
5429
static PyObject *
5325
5430
BlockIndex_shape_getter (BlockIndexObject * self , void * Py_UNUSED (closure ))
5326
5431
{
5327
5432
if (self -> shape == NULL || self -> shape_recache ) {
5328
5433
Py_XDECREF (self -> shape ); // get rid of old if it exists
5329
- self -> shape = AK_build_pair_ssize_t (self -> row_count , self -> bir_count );
5434
+ self -> shape = AK_build_pair_ssize_t (
5435
+ AK_BI_ROWS (self -> row_count ),
5436
+ self -> bir_count );
5330
5437
}
5331
5438
// shape is not null and shape_recache is false
5332
5439
Py_INCREF (self -> shape ); // for caller
@@ -5336,7 +5443,7 @@ BlockIndex_shape_getter(BlockIndexObject *self, void* Py_UNUSED(closure))
5336
5443
5337
5444
static PyObject *
5338
5445
BlockIndex_rows_getter (BlockIndexObject * self , void * Py_UNUSED (closure )){
5339
- return PyLong_FromSsize_t (self -> row_count );
5446
+ return PyLong_FromSsize_t (AK_BI_ROWS ( self -> row_count ) );
5340
5447
}
5341
5448
5342
5449
static PyObject *
@@ -5457,13 +5564,18 @@ BlockIndex_get_column(BlockIndexObject *self, PyObject *key){
5457
5564
5458
5565
static PyObject *
5459
5566
BlockIndex_iter (BlockIndexObject * self ) {
5460
- return BIIter_new (self , 0 );
5567
+ return BIIter_new (self , false);
5568
+ }
5569
+
5570
+ static PyObject *
5571
+ BlockIndex_reversed (BlockIndexObject * self ) {
5572
+ return BIIter_new (self , true);
5461
5573
}
5462
5574
5463
5575
// Given key, return an iterator of a selection.
5464
5576
static PyObject *
5465
5577
BlockIndex_iter_select (BlockIndexObject * self , PyObject * selector ){
5466
- return BIIterSelector_new (self , selector , 0 , BIIS_UNKNOWN , 0 );
5578
+ return BIIterSelector_new (self , selector , false , BIIS_UNKNOWN , false );
5467
5579
}
5468
5580
5469
5581
static char * iter_contiguous_kargs_names [] = {
@@ -5478,7 +5590,7 @@ static PyObject*
5478
5590
BlockIndex_iter_contiguous (BlockIndexObject * self , PyObject * args , PyObject * kwargs )
5479
5591
{
5480
5592
PyObject * selector ;
5481
- int ascending = 0 ;
5593
+ int ascending = 0 ; // must be int for parsing to "p"
5482
5594
int reduce = 0 ;
5483
5595
5484
5596
if (!PyArg_ParseTupleAndKeywords (args , kwargs ,
@@ -5490,14 +5602,21 @@ BlockIndex_iter_contiguous(BlockIndexObject *self, PyObject *args, PyObject *kwa
5490
5602
)) {
5491
5603
return NULL ;
5492
5604
}
5493
- PyObject * iter = BIIterSelector_new (self , selector , 0 , BIIS_UNKNOWN , ascending );
5605
+ PyObject * iter = BIIterSelector_new (self , selector , false , BIIS_UNKNOWN , ascending );
5494
5606
if (iter == NULL ) {
5495
5607
return NULL ; // exception set
5496
5608
}
5497
- PyObject * biiter = BIIterContiguous_new (self , 0 , iter , reduce ); // might be NULL, steals iter ref
5609
+ PyObject * biiter = BIIterContiguous_new (self , false , iter , reduce ); // might be NULL, steals iter ref
5498
5610
return biiter ;
5499
5611
}
5500
5612
5613
+ // Given key, return an iterator of a selection.
5614
+ static PyObject *
5615
+ BlockIndex_iter_block (BlockIndexObject * self ){
5616
+ return BIIterBlock_new (self , false);
5617
+ }
5618
+
5619
+
5501
5620
//------------------------------------------------------------------------------
5502
5621
// slot / method def
5503
5622
@@ -5512,6 +5631,7 @@ static PyMethodDef BlockIndex_methods[] = {
5512
5631
{"__getstate__" , (PyCFunction ) BlockIndex_getstate , METH_NOARGS , NULL },
5513
5632
{"__setstate__" , (PyCFunction ) BlockIndex_setstate , METH_O , NULL },
5514
5633
{"__sizeof__" , (PyCFunction ) BlockIndex_sizeof , METH_NOARGS , NULL },
5634
+ {"__reversed__" , (PyCFunction ) BlockIndex_reversed , METH_NOARGS , NULL },
5515
5635
{"to_list" , (PyCFunction )BlockIndex_to_list , METH_NOARGS , NULL },
5516
5636
{"to_bytes" , (PyCFunction )BlockIndex_to_bytes , METH_NOARGS , NULL },
5517
5637
{"copy" , (PyCFunction )BlockIndex_copy , METH_NOARGS , NULL },
@@ -5522,6 +5642,7 @@ static PyMethodDef BlockIndex_methods[] = {
5522
5642
(PyCFunction ) BlockIndex_iter_contiguous ,
5523
5643
METH_VARARGS | METH_KEYWORDS ,
5524
5644
NULL },
5645
+ {"iter_block" , (PyCFunction ) BlockIndex_iter_block , METH_NOARGS , NULL },
5525
5646
// {"__getnewargs__", (PyCFunction)BlockIndex_getnewargs, METH_NOARGS, NULL},
5526
5647
{NULL },
5527
5648
};
@@ -5550,7 +5671,7 @@ static PyTypeObject BlockIndexType = {
5550
5671
//------------------------------------------------------------------------------
5551
5672
5552
5673
typedef struct {
5553
- PyObject_VAR_HEAD
5674
+ PyObject_HEAD
5554
5675
PyObject * array ;
5555
5676
PyObject * list ;
5556
5677
} ArrayGOObject ;
@@ -5899,6 +6020,8 @@ PyInit__arraykit(void)
5899
6020
PyType_Ready (& BIIterSeqType ) ||
5900
6021
PyType_Ready (& BIIterSliceType ) ||
5901
6022
PyType_Ready (& BIIterBoolType ) ||
6023
+ PyType_Ready (& BIIterContiguousType ) ||
6024
+ PyType_Ready (& BIIterBlockType ) ||
5902
6025
PyType_Ready (& ArrayGOType ) ||
5903
6026
PyModule_AddObject (m , "BlockIndex" , (PyObject * ) & BlockIndexType ) ||
5904
6027
PyModule_AddObject (m , "ArrayGO" , (PyObject * ) & ArrayGOType ) ||
0 commit comments