@@ -3894,11 +3894,9 @@ PyArray_FromString(char *data, npy_intp slen, PyArray_Descr *dtype,
3894
3894
NPY_NO_EXPORT PyObject *
3895
3895
PyArray_FromIter (PyObject * obj , PyArray_Descr * dtype , npy_intp count )
3896
3896
{
3897
- PyObject * value ;
3898
3897
PyObject * iter = NULL ;
3899
3898
PyArrayObject * ret = NULL ;
3900
3899
npy_intp i , elsize , elcount ;
3901
- char * item , * new_data ;
3902
3900
3903
3901
if (dtype == NULL ) {
3904
3902
return NULL ;
@@ -3910,6 +3908,7 @@ PyArray_FromIter(PyObject *obj, PyArray_Descr *dtype, npy_intp count)
3910
3908
}
3911
3909
3912
3910
if (PyDataType_ISUNSIZED (dtype )) {
3911
+ /* If this error is removed, the `ret` allocation may need fixing */
3913
3912
PyErr_SetString (PyExc_ValueError ,
3914
3913
"Must specify length when using variable-size data-type." );
3915
3914
goto done ;
@@ -3927,38 +3926,50 @@ PyArray_FromIter(PyObject *obj, PyArray_Descr *dtype, npy_intp count)
3927
3926
elsize = dtype -> elsize ;
3928
3927
3929
3928
/*
3930
- * We would need to alter the memory RENEW code to decrement any
3931
- * reference counts before throwing away any memory.
3929
+ * Note that PyArray_DESCR(ret) may not match dtype. There are exactly
3930
+ * two cases where this can happen: empty strings/bytes/void (rejected
3931
+ * above) and subarray dtypes (supported by sticking with `dtype`).
3932
3932
*/
3933
- if (PyDataType_REFCHK (dtype )) {
3934
- PyErr_SetString (PyExc_ValueError ,
3935
- "cannot create object arrays from iterator" );
3936
- goto done ;
3937
- }
3938
-
3933
+ Py_INCREF (dtype );
3939
3934
ret = (PyArrayObject * )PyArray_NewFromDescr (& PyArray_Type , dtype , 1 ,
3940
3935
& elcount , NULL ,NULL , 0 , NULL );
3941
- dtype = NULL ;
3942
3936
if (ret == NULL ) {
3943
3937
goto done ;
3944
3938
}
3945
- for (i = 0 ; (i < count || count == -1 ) &&
3946
- (value = PyIter_Next (iter )); i ++ ) {
3947
- if (i >= elcount && elsize != 0 ) {
3939
+ #ifdef NPY_RELAXED_STRIDES_DEBUG
3940
+ /* Incompatible with NPY_RELAXED_STRIDES_DEBUG due to growing */
3941
+ if (elcount == 1 ) {
3942
+ PyArray_STRIDES (ret )[0 ] = elsize ;
3943
+ }
3944
+ #endif /* NPY_RELAXED_STRIDES_DEBUG */
3945
+
3946
+
3947
+ char * item = PyArray_BYTES (ret );
3948
+ for (i = 0 ; i < count || count == -1 ; i ++ , item += elsize ) {
3949
+ PyObject * value = PyIter_Next (iter );
3950
+ if (value == NULL ) {
3951
+ if (PyErr_Occurred ()) {
3952
+ /* Fetching next item failed rather than exhausting iterator */
3953
+ goto done ;
3954
+ }
3955
+ break ;
3956
+ }
3957
+
3958
+ if (NPY_UNLIKELY (i >= elcount ) && elsize != 0 ) {
3959
+ char * new_data = NULL ;
3948
3960
npy_intp nbytes ;
3949
3961
/*
3950
3962
Grow PyArray_DATA(ret):
3951
3963
this is similar for the strategy for PyListObject, but we use
3952
3964
50% overallocation => 0, 4, 8, 14, 23, 36, 56, 86 ...
3965
+ TODO: The loadtxt code now uses a `growth` helper that would
3966
+ be suitable to reuse here.
3953
3967
*/
3954
3968
elcount = (i >> 1 ) + (i < 4 ? 4 : 2 ) + i ;
3955
3969
if (!npy_mul_with_overflow_intp (& nbytes , elcount , elsize )) {
3956
3970
/* The handler is always valid */
3957
- new_data = PyDataMem_UserRENEW (PyArray_DATA (ret ), nbytes ,
3958
- PyArray_HANDLER (ret ));
3959
- }
3960
- else {
3961
- new_data = NULL ;
3971
+ new_data = PyDataMem_UserRENEW (
3972
+ PyArray_BYTES (ret ), nbytes , PyArray_HANDLER (ret ));
3962
3973
}
3963
3974
if (new_data == NULL ) {
3964
3975
PyErr_SetString (PyExc_MemoryError ,
@@ -3967,44 +3978,52 @@ PyArray_FromIter(PyObject *obj, PyArray_Descr *dtype, npy_intp count)
3967
3978
goto done ;
3968
3979
}
3969
3980
((PyArrayObject_fields * )ret )-> data = new_data ;
3981
+ /* resize array for cleanup: */
3982
+ PyArray_DIMS (ret )[0 ] = elcount ;
3983
+ /* Reset `item` pointer to point into realloc'd chunk */
3984
+ item = new_data + i * elsize ;
3985
+ if (PyDataType_FLAGCHK (dtype , NPY_NEEDS_INIT )) {
3986
+ /* Initialize new chunk: */
3987
+ memset (item , 0 , nbytes - i * elsize );
3988
+ }
3970
3989
}
3971
- PyArray_DIMS (ret )[0 ] = i + 1 ;
3972
3990
3973
- if (((item = index2ptr (ret , i )) == NULL ) ||
3974
- PyArray_SETITEM (ret , item , value ) == -1 ) {
3991
+ if (PyArray_Pack (dtype , item , value ) < 0 ) {
3975
3992
Py_DECREF (value );
3976
3993
goto done ;
3977
3994
}
3978
3995
Py_DECREF (value );
3979
3996
}
3980
3997
3981
3998
3982
- if (PyErr_Occurred ()) {
3983
- goto done ;
3984
- }
3985
3999
if (i < count ) {
3986
- PyErr_SetString (PyExc_ValueError ,
3987
- "iterator too short" );
4000
+ PyErr_Format (PyExc_ValueError ,
4001
+ "iterator too short: Expected %zd but iterator had only %zd "
4002
+ "items." , (Py_ssize_t )count , (Py_ssize_t )i );
3988
4003
goto done ;
3989
4004
}
3990
4005
3991
4006
/*
3992
- * Realloc the data so that don't keep extra memory tied up
3993
- * (assuming realloc is reasonably good about reusing space...)
4007
+ * Realloc the data so that don't keep extra memory tied up and fix
4008
+ * the arrays first dimension (there could be more than one).
3994
4009
*/
3995
4010
if (i == 0 || elsize == 0 ) {
3996
4011
/* The size cannot be zero for realloc. */
3997
- goto done ;
3998
4012
}
3999
- /* The handler is always valid */
4000
- new_data = PyDataMem_UserRENEW (PyArray_DATA (ret ), i * elsize ,
4001
- PyArray_HANDLER (ret ));
4002
- if (new_data == NULL ) {
4003
- PyErr_SetString (PyExc_MemoryError ,
4004
- "cannot allocate array memory" );
4005
- goto done ;
4013
+ else {
4014
+ /* Resize array to actual final size (it may be too large) */
4015
+ /* The handler is always valid */
4016
+ char * new_data = PyDataMem_UserRENEW (
4017
+ PyArray_DATA (ret ), i * elsize , PyArray_HANDLER (ret ));
4018
+
4019
+ if (new_data == NULL ) {
4020
+ PyErr_SetString (PyExc_MemoryError ,
4021
+ "cannot allocate array memory" );
4022
+ goto done ;
4023
+ }
4024
+ ((PyArrayObject_fields * )ret )-> data = new_data ;
4006
4025
}
4007
- (( PyArrayObject_fields * ) ret )-> data = new_data ;
4026
+ PyArray_DIMS ( ret )[ 0 ] = i ;
4008
4027
4009
4028
done :
4010
4029
Py_XDECREF (iter );
0 commit comments