@@ -519,6 +519,9 @@ static npy_longlong
519
519
string_to_uint (char * in , npy_ulonglong * value )
520
520
{
521
521
PyObject * pylong_value = string_to_pylong (in );
522
+ if (pylong_value == NULL ) {
523
+ return -1 ;
524
+ }
522
525
* value = PyLong_AsUnsignedLongLong (pylong_value );
523
526
if (* value == (unsigned long long )-1 && PyErr_Occurred ()) {
524
527
Py_DECREF (pylong_value );
@@ -542,13 +545,13 @@ string_to_int(char *in, npy_longlong *value)
542
545
}
543
546
544
547
static int
545
- pylong_to_string (PyObject * pylong_val , char * out )
548
+ pyobj_to_string (PyObject * obj , char * out )
546
549
{
547
- if (pylong_val == NULL ) {
550
+ if (obj == NULL ) {
548
551
return -1 ;
549
552
}
550
- PyObject * pystr_val = PyObject_Str (pylong_val );
551
- Py_DECREF (pylong_val );
553
+ PyObject * pystr_val = PyObject_Str (obj );
554
+ Py_DECREF (obj );
552
555
if (pystr_val == NULL ) {
553
556
return -1 ;
554
557
}
@@ -573,14 +576,14 @@ static int
573
576
int_to_string (long long in , char * out )
574
577
{
575
578
PyObject * pylong_val = PyLong_FromLongLong (in );
576
- return pylong_to_string (pylong_val , out );
579
+ return pyobj_to_string (pylong_val , out );
577
580
}
578
581
579
582
static int
580
583
uint_to_string (unsigned long long in , char * out )
581
584
{
582
585
PyObject * pylong_val = PyLong_FromUnsignedLongLong (in );
583
- return pylong_to_string (pylong_val , out );
586
+ return pyobj_to_string (pylong_val , out );
584
587
}
585
588
586
589
#define STRING_INT_CASTS (typename , typekind , shortname , numpy_tag , \
@@ -663,6 +666,7 @@ uint_to_string(unsigned long long in, char *out)
663
666
if (typekind##_to_string((longtype)*in, out) != 0) { \
664
667
return -1; \
665
668
} \
669
+ \
666
670
in += in_stride; \
667
671
out += out_stride; \
668
672
} \
@@ -678,7 +682,7 @@ uint_to_string(unsigned long long in, char *out)
678
682
\
679
683
static char *shortname##2s_name = "cast_" #typename "_to_StringDType";
680
684
681
- #define INT_DTYPES_AND_CAST_SPEC (shortname , typename ) \
685
+ #define DTYPES_AND_CAST_SPEC (shortname , typename ) \
682
686
PyArray_DTypeMeta **s2##shortname##_dtypes = \
683
687
get_dtypes(this, &PyArray_##typename##DType); \
684
688
\
@@ -733,6 +737,175 @@ STRING_INT_CASTS(ulonglong, uint, ulonglong, NPY_ULONGLONG, llu, npy_ulonglong,
733
737
unsigned long long)
734
738
#endif
735
739
740
+ static PyObject *
741
+ string_to_pyfloat (char * in )
742
+ {
743
+ ss * s = (ss * )in ;
744
+ if (ss_isnull (s )) {
745
+ PyErr_SetString (
746
+ PyExc_ValueError ,
747
+ "Arrays with missing data cannot be converted to integers" );
748
+ return NULL ;
749
+ }
750
+ PyObject * val_obj = PyUnicode_FromStringAndSize (s -> buf , s -> len );
751
+ if (val_obj == NULL ) {
752
+ return NULL ;
753
+ }
754
+ PyObject * pyfloat_value = PyFloat_FromString (val_obj );
755
+ Py_DECREF (val_obj );
756
+ return pyfloat_value ;
757
+ }
758
+
759
+ #define STRING_TO_FLOAT_CAST (typename , shortname , isinf_name , \
760
+ double_to_float ) \
761
+ static int string_to_##typename( \
762
+ PyArrayMethod_Context * NPY_UNUSED(context), char *const data[], \
763
+ npy_intp const dimensions[], npy_intp const strides[], \
764
+ NpyAuxData *NPY_UNUSED(auxdata)) \
765
+ { \
766
+ npy_intp N = dimensions[0]; \
767
+ char *in = data[0]; \
768
+ npy_##typename *out = (npy_##typename *)data[1]; \
769
+ \
770
+ npy_intp in_stride = strides[0]; \
771
+ npy_intp out_stride = strides[1] / sizeof(npy_##typename); \
772
+ \
773
+ while (N--) { \
774
+ PyObject *pyfloat_value = string_to_pyfloat(in); \
775
+ if (pyfloat_value == NULL) { \
776
+ return -1; \
777
+ } \
778
+ double dval = PyFloat_AS_DOUBLE(pyfloat_value); \
779
+ npy_##typename fval = (double_to_float)(dval); \
780
+ \
781
+ if (NPY_UNLIKELY(isinf_name(fval) && !(npy_isinf(dval)))) { \
782
+ /* we need to somehow use numpy's floating point error */ \
783
+ /* handling, which supports lots more functionality but */ \
784
+ /* isn't exposed in the C API */ \
785
+ PyErr_SetString (PyExc_FloatingPointError , \
786
+ "overflow encountered in cast" ); \
787
+ return -1 ; \
788
+ } \
789
+ \
790
+ * out = fval ; \
791
+ \
792
+ in += in_stride ; \
793
+ out += out_stride ; \
794
+ } \
795
+ \
796
+ return 0 ; \
797
+ } \
798
+ \
799
+ static PyType_Slot s2 ##shortname ##_slots[] = { \
800
+ {NPY_METH_resolve_descriptors, \
801
+ &string_to_##typename##_resolve_descriptors}, \
802
+ {NPY_METH_strided_loop, &string_to_##typename}, \
803
+ {0, NULL}}; \
804
+ \
805
+ static char *s2##shortname##_name = "cast_StringDType_to_" #typename;
806
+
807
+ #define STRING_TO_FLOAT_RESOLVE_DESCRIPTORS (typename , npy_typename ) \
808
+ static NPY_CASTING string_to_##typename##_resolve_descriptors( \
809
+ PyObject *NPY_UNUSED(self), \
810
+ PyArray_DTypeMeta *NPY_UNUSED(dtypes[2]), \
811
+ PyArray_Descr *given_descrs[2], PyArray_Descr *loop_descrs[2], \
812
+ npy_intp *NPY_UNUSED(view_offset)) \
813
+ { \
814
+ if (given_descrs[1] == NULL) { \
815
+ loop_descrs[1] = PyArray_DescrNewFromType(NPY_##npy_typename); \
816
+ } \
817
+ else { \
818
+ Py_INCREF(given_descrs[1]); \
819
+ loop_descrs[1] = given_descrs[1]; \
820
+ } \
821
+ \
822
+ Py_INCREF(given_descrs[0]); \
823
+ loop_descrs[0] = given_descrs[0]; \
824
+ \
825
+ return NPY_UNSAFE_CASTING; \
826
+ }
827
+
828
+ #define FLOAT_TO_STRING_CAST (typename , shortname , float_to_double ) \
829
+ static int typename##_to_string( \
830
+ PyArrayMethod_Context *NPY_UNUSED(context), char *const data[], \
831
+ npy_intp const dimensions[], npy_intp const strides[], \
832
+ NpyAuxData *NPY_UNUSED(auxdata)) \
833
+ { \
834
+ npy_intp N = dimensions[0]; \
835
+ npy_##typename *in = (npy_##typename *)data[0]; \
836
+ char *out = data[1]; \
837
+ \
838
+ npy_intp in_stride = strides[0] / sizeof(npy_##typename); \
839
+ npy_intp out_stride = strides[1]; \
840
+ \
841
+ while (N--) { \
842
+ PyObject *pyfloat_val = \
843
+ PyFloat_FromDouble((float_to_double)(*in)); \
844
+ if (pyobj_to_string(pyfloat_val, out) == -1) { \
845
+ return -1; \
846
+ } \
847
+ \
848
+ in += in_stride; \
849
+ out += out_stride; \
850
+ } \
851
+ \
852
+ return 0; \
853
+ } \
854
+ \
855
+ static PyType_Slot shortname##2s_slots [] = { \
856
+ {NPY_METH_resolve_descriptors, \
857
+ &any_to_string_UNSAFE_resolve_descriptors}, \
858
+ {NPY_METH_strided_loop, &typename##_to_string}, \
859
+ {0, NULL}}; \
860
+ \
861
+ static char *shortname##2s_name = "cast_" #typename "_to_StringDType";
862
+
863
+ STRING_TO_FLOAT_RESOLVE_DESCRIPTORS (float64 , DOUBLE )
864
+
865
+ static int
866
+ string_to_float64 (PyArrayMethod_Context * NPY_UNUSED (context ),
867
+ char * const data [], npy_intp const dimensions [],
868
+ npy_intp const strides [], NpyAuxData * NPY_UNUSED (auxdata ))
869
+ {
870
+ npy_intp N = dimensions [0 ];
871
+ char * in = data [0 ];
872
+ npy_float64 * out = (npy_float64 * )data [1 ];
873
+
874
+ npy_intp in_stride = strides [0 ];
875
+ npy_intp out_stride = strides [1 ] / sizeof (npy_float64 );
876
+
877
+ while (N -- ) {
878
+ PyObject * pyfloat_value = string_to_pyfloat (in );
879
+ if (pyfloat_value == NULL ) {
880
+ return -1 ;
881
+ }
882
+ * out = (npy_float64 )PyFloat_AS_DOUBLE (pyfloat_value );
883
+ Py_DECREF (pyfloat_value );
884
+
885
+ in += in_stride ;
886
+ out += out_stride ;
887
+ }
888
+
889
+ return 0 ;
890
+ }
891
+
892
+ static PyType_Slot s2f64_slots [] = {
893
+ {NPY_METH_resolve_descriptors , & string_to_float64_resolve_descriptors },
894
+ {NPY_METH_strided_loop , & string_to_float64 },
895
+ {0 , NULL }};
896
+
897
+ static char * s2f64_name = "cast_StringDType_to_float64" ;
898
+
899
+ FLOAT_TO_STRING_CAST (float64 , f64 , double )
900
+
901
+ STRING_TO_FLOAT_RESOLVE_DESCRIPTORS (float32 , FLOAT )
902
+ STRING_TO_FLOAT_CAST (float32 , f32 , npy_isinf , npy_float32 )
903
+ FLOAT_TO_STRING_CAST (float32 , f32 , double )
904
+
905
+ STRING_TO_FLOAT_RESOLVE_DESCRIPTORS (float16 , HALF )
906
+ STRING_TO_FLOAT_CAST (float16 , f16 , npy_half_isinf , npy_double_to_half )
907
+ FLOAT_TO_STRING_CAST (float16 , f16 , npy_half_to_double )
908
+
736
909
PyArrayMethod_Spec *
737
910
get_cast_spec (const char * name , NPY_CASTING casting ,
738
911
NPY_ARRAYMETHOD_FLAGS flags , PyArray_DTypeMeta * * dtypes ,
@@ -785,7 +958,7 @@ get_casts(PyArray_DTypeMeta *this, PyArray_DTypeMeta *other)
785
958
786
959
int is_pandas = (this == (PyArray_DTypeMeta * )& PandasStringDType );
787
960
788
- int num_casts = 21 ;
961
+ int num_casts = 27 ;
789
962
790
963
#if NPY_SIZEOF_BYTE == NPY_SIZEOF_SHORT
791
964
num_casts += 4 ;
@@ -840,34 +1013,37 @@ get_casts(PyArray_DTypeMeta *this, PyArray_DTypeMeta *other)
840
1013
b2s_name , NPY_SAFE_CASTING , NPY_METH_NO_FLOATINGPOINT_ERRORS ,
841
1014
b2s_dtypes , b2s_slots );
842
1015
843
- INT_DTYPES_AND_CAST_SPEC (i8 , Int8 )
844
- INT_DTYPES_AND_CAST_SPEC (i16 , Int16 )
845
- INT_DTYPES_AND_CAST_SPEC (i32 , Int32 )
846
- INT_DTYPES_AND_CAST_SPEC (i64 , Int64 )
847
- INT_DTYPES_AND_CAST_SPEC (u8 , UInt8 )
848
- INT_DTYPES_AND_CAST_SPEC (u16 , UInt16 )
849
- INT_DTYPES_AND_CAST_SPEC (u32 , UInt32 )
850
- INT_DTYPES_AND_CAST_SPEC (u64 , UInt64 )
1016
+ DTYPES_AND_CAST_SPEC (i8 , Int8 )
1017
+ DTYPES_AND_CAST_SPEC (i16 , Int16 )
1018
+ DTYPES_AND_CAST_SPEC (i32 , Int32 )
1019
+ DTYPES_AND_CAST_SPEC (i64 , Int64 )
1020
+ DTYPES_AND_CAST_SPEC (u8 , UInt8 )
1021
+ DTYPES_AND_CAST_SPEC (u16 , UInt16 )
1022
+ DTYPES_AND_CAST_SPEC (u32 , UInt32 )
1023
+ DTYPES_AND_CAST_SPEC (u64 , UInt64 )
851
1024
#if NPY_SIZEOF_BYTE == NPY_SIZEOF_SHORT
852
- INT_DTYPES_AND_CAST_SPEC (byte , Byte )
853
- INT_DTYPES_AND_CAST_SPEC (ubyte , UByte )
1025
+ DTYPES_AND_CAST_SPEC (byte , Byte )
1026
+ DTYPES_AND_CAST_SPEC (ubyte , UByte )
854
1027
#endif
855
1028
#if NPY_SIZEOF_SHORT == NPY_SIZEOF_INT
856
- INT_DTYPES_AND_CAST_SPEC (short , Short )
857
- INT_DTYPES_AND_CAST_SPEC (ushort , UShort )
1029
+ DTYPES_AND_CAST_SPEC (short , Short )
1030
+ DTYPES_AND_CAST_SPEC (ushort , UShort )
858
1031
#endif
859
1032
#if NPY_SIZEOF_INT == NPY_SIZEOF_LONG
860
- INT_DTYPES_AND_CAST_SPEC (int , Int )
861
- INT_DTYPES_AND_CAST_SPEC (uint , UInt )
1033
+ DTYPES_AND_CAST_SPEC (int , Int )
1034
+ DTYPES_AND_CAST_SPEC (uint , UInt )
862
1035
#endif
863
1036
#if NPY_SIZEOF_LONGLONG == NPY_SIZEOF_LONG
864
- INT_DTYPES_AND_CAST_SPEC (longlong , LongLong )
865
- INT_DTYPES_AND_CAST_SPEC (ulonglong , ULongLong )
1037
+ DTYPES_AND_CAST_SPEC (longlong , LongLong )
1038
+ DTYPES_AND_CAST_SPEC (ulonglong , ULongLong )
866
1039
#endif
867
1040
868
- PyArrayMethod_Spec * * casts = NULL ;
1041
+ DTYPES_AND_CAST_SPEC (f64 , Double )
1042
+ DTYPES_AND_CAST_SPEC (f32 , Float )
1043
+ DTYPES_AND_CAST_SPEC (f16 , Half )
869
1044
870
- casts = malloc ((num_casts + 1 ) * sizeof (PyArrayMethod_Spec * ));
1045
+ PyArrayMethod_Spec * * casts =
1046
+ malloc ((num_casts + 1 ) * sizeof (PyArrayMethod_Spec * ));
871
1047
872
1048
int cast_i = 0 ;
873
1049
@@ -916,6 +1092,12 @@ get_casts(PyArray_DTypeMeta *this, PyArray_DTypeMeta *other)
916
1092
casts [cast_i ++ ] = StringToULongLongCastSpec ;
917
1093
casts [cast_i ++ ] = ULongLongToStringCastSpec ;
918
1094
#endif
1095
+ casts [cast_i ++ ] = StringToDoubleCastSpec ;
1096
+ casts [cast_i ++ ] = DoubleToStringCastSpec ;
1097
+ casts [cast_i ++ ] = StringToFloatCastSpec ;
1098
+ casts [cast_i ++ ] = FloatToStringCastSpec ;
1099
+ casts [cast_i ++ ] = StringToHalfCastSpec ;
1100
+ casts [cast_i ++ ] = HalfToStringCastSpec ;
919
1101
if (is_pandas ) {
920
1102
casts [cast_i ++ ] = ThisToOtherCastSpec ;
921
1103
casts [cast_i ++ ] = OtherToThisCastSpec ;
0 commit comments