@@ -4178,6 +4178,8 @@ typedef struct BlockIndexObject {
4178
4178
Py_ssize_t bir_capacity ;
4179
4179
BlockIndexRecord * bir ;
4180
4180
PyArray_Descr * dtype ;
4181
+ int8_t shape_recache ;
4182
+ PyObject * shape ;
4181
4183
} BlockIndexObject ;
4182
4184
4183
4185
@@ -4341,7 +4343,7 @@ BIIterSeq_iternext(BIIterSeqObject *self) {
4341
4343
PyArrayObject * a = (PyArrayObject * )self -> selector ;
4342
4344
switch (PyArray_TYPE (a )) { // type of passed in array
4343
4345
case NPY_INT64 :
4344
- t = * (npy_int64 * )PyArray_GETPTR1 (a , i );
4346
+ t = ( Py_ssize_t ) * (npy_int64 * )PyArray_GETPTR1 (a , i );
4345
4347
break ;
4346
4348
case NPY_INT32 :
4347
4349
t = * (npy_int32 * )PyArray_GETPTR1 (a , i );
@@ -4353,7 +4355,7 @@ BIIterSeq_iternext(BIIterSeqObject *self) {
4353
4355
t = * (npy_int8 * )PyArray_GETPTR1 (a , i );
4354
4356
break ;
4355
4357
case NPY_UINT64 :
4356
- t = * (npy_uint64 * )PyArray_GETPTR1 (a , i );
4358
+ t = ( Py_ssize_t ) * (npy_uint64 * )PyArray_GETPTR1 (a , i );
4357
4359
break ;
4358
4360
case NPY_UINT32 :
4359
4361
t = * (npy_uint32 * )PyArray_GETPTR1 (a , i );
@@ -4776,6 +4778,9 @@ BlockIndex_init(PyObject *self, PyObject *args, PyObject *kwargs) {
4776
4778
bi -> bir_count = bir_count ;
4777
4779
bi -> bir_capacity = bir_capacity ;
4778
4780
4781
+ bi -> shape_recache = 1 ; // always init to true
4782
+ bi -> shape = NULL ;
4783
+
4779
4784
// Load the bi->bir struct array, if defined
4780
4785
bi -> bir = NULL ;
4781
4786
// always set bi to capacity defined at this point
@@ -4800,6 +4805,7 @@ BlockIndex_init(PyObject *self, PyObject *args, PyObject *kwargs) {
4800
4805
return -1 ;
4801
4806
}
4802
4807
}
4808
+
4803
4809
return 0 ;
4804
4810
}
4805
4811
@@ -4808,9 +4814,9 @@ BlockIndex_dealloc(BlockIndexObject *self) {
4808
4814
if (self -> bir != NULL ) {
4809
4815
PyMem_Free (self -> bir );
4810
4816
}
4811
- if ( self -> dtype != NULL ) {
4812
- Py_DECREF ((PyObject * )self -> dtype );
4813
- }
4817
+ // both dtype and shape might not be set
4818
+ Py_XDECREF ((PyObject * )self -> dtype );
4819
+ Py_XDECREF ( self -> shape );
4814
4820
Py_TYPE (self )-> tp_free ((PyObject * )self );
4815
4821
}
4816
4822
@@ -4841,7 +4847,7 @@ BlockIndex_register(BlockIndexObject *self, PyObject *value) {
4841
4847
}
4842
4848
Py_ssize_t increment = ndim == 1 ? 1 : PyArray_DIM (a , 1 );
4843
4849
4844
- // assign alignment on first observation; otherwise take
4850
+ // assign alignment on first observation; otherwise force alignemnt. We do this regardless of if the array has no columns.
4845
4851
Py_ssize_t alignment = PyArray_DIM (a , 0 );
4846
4852
if (self -> row_count == -1 ) {
4847
4853
self -> row_count = alignment ;
@@ -4854,16 +4860,20 @@ BlockIndex_register(BlockIndexObject *self, PyObject *value) {
4854
4860
return NULL ;
4855
4861
}
4856
4862
4863
+ // if we are not adding columns, we are not adding types, so we are not changing the dtype or shape
4857
4864
if (increment == 0 ) {
4858
4865
Py_RETURN_FALSE ;
4859
4866
}
4860
4867
4868
+
4861
4869
PyArray_Descr * dt = PyArray_DESCR (a ); // borrowed ref
4862
- if (self -> dtype == NULL ) {
4870
+ self -> shape_recache = 1 ; // adjusting columns, must recache shape
4871
+
4872
+ if (self -> dtype == NULL ) { // if not already set
4863
4873
Py_INCREF ((PyObject * )dt );
4864
4874
self -> dtype = dt ;
4865
4875
}
4866
- else if (!PyDataType_ISOBJECT (self -> dtype )) {
4876
+ else if (!PyDataType_ISOBJECT (self -> dtype )) { // if object cannot resolve further
4867
4877
PyArray_Descr * dtr = AK_ResolveDTypes (self -> dtype , dt ); // new ref
4868
4878
Py_DECREF ((PyObject * )self -> dtype );
4869
4879
self -> dtype = dtr ;
@@ -4972,6 +4982,9 @@ BlockIndex_copy(BlockIndexObject *self, PyObject *Py_UNUSED(unused))
4972
4982
bi -> bir_count = self -> bir_count ;
4973
4983
bi -> bir_capacity = self -> bir_capacity ;
4974
4984
4985
+ bi -> shape_recache = 1 ; // could copy, but do not want to copy a pending cache state
4986
+ bi -> shape = NULL ;
4987
+
4975
4988
bi -> bir = NULL ;
4976
4989
AK_BI_BIR_new (bi ); // do initial alloc to self->bir_capacity
4977
4990
memcpy (bi -> bir ,
@@ -4993,9 +5006,16 @@ BlockIndex_iter(BlockIndexObject* self) {
4993
5006
4994
5007
4995
5008
static PyObject *
4996
- BlockIndex_shape_getter (BlockIndexObject * self , void * Py_UNUSED (closure )){
4997
- // NOTE: this could be cached
4998
- return Py_BuildValue ("nn" , self -> row_count , self -> bir_count );
5009
+ BlockIndex_shape_getter (BlockIndexObject * self , void * Py_UNUSED (closure ))
5010
+ {
5011
+ if (self -> shape == NULL || self -> shape_recache ) {
5012
+ Py_XDECREF (self -> shape ); // get rid of old if it exists
5013
+ self -> shape = Py_BuildValue ("nn" , self -> row_count , self -> bir_count ); // new ref
5014
+ }
5015
+ // shape is not null and shape_recache is false
5016
+ Py_INCREF (self -> shape ); // for caller
5017
+ self -> shape_recache = 0 ;
5018
+ return self -> shape ;
4999
5019
}
5000
5020
5001
5021
static PyObject *
0 commit comments