@@ -449,6 +449,124 @@ static PyType_Slot s2b_slots[] = {
449
449
450
450
static char * s2b_name = "cast_StringDType_to_Bool" ;
451
451
452
+ // object to string
453
+
454
+ typedef struct {
455
+ NpyAuxData base ;
456
+ PyArray_Descr * descr ;
457
+ int move_references ;
458
+ } _object_to_string_auxdata ;
459
+
460
+ static void
461
+ _object_to_string_auxdata_free (NpyAuxData * auxdata )
462
+ {
463
+ _object_to_string_auxdata * data = (_object_to_string_auxdata * )auxdata ;
464
+ Py_DECREF (data -> descr );
465
+ PyMem_Free (data );
466
+ }
467
+
468
+ static NpyAuxData *
469
+ _object_to_string_auxdata_clone (NpyAuxData * data )
470
+ {
471
+ _object_to_string_auxdata * res = PyMem_Malloc (sizeof (* res ));
472
+ if (res == NULL ) {
473
+ return NULL ;
474
+ }
475
+ memcpy (res , data , sizeof (* res ));
476
+ Py_INCREF (res -> descr );
477
+ return (NpyAuxData * )res ;
478
+ }
479
+
480
+ static int
481
+ object_to_string_strided_loop (PyArrayMethod_Context * NPY_UNUSED (context ),
482
+ char * const * args , const npy_intp * dimensions ,
483
+ const npy_intp * strides , NpyAuxData * auxdata )
484
+ {
485
+ npy_intp N = dimensions [0 ];
486
+ char * src = args [0 ], * dst = args [1 ];
487
+ npy_intp src_stride = strides [0 ], dst_stride = strides [1 ];
488
+ _object_to_string_auxdata * data = (_object_to_string_auxdata * )auxdata ;
489
+
490
+ PyObject * src_ref ;
491
+
492
+ while (N > 0 ) {
493
+ memcpy (& src_ref , src , sizeof (src_ref ));
494
+ if (stringdtype_setitem ((StringDTypeObject * )(data -> descr ),
495
+ src_ref ? src_ref : Py_None ,
496
+ (void * )dst ) < 0 ) {
497
+ return -1 ;
498
+ }
499
+
500
+ if (data -> move_references && src_ref != NULL ) {
501
+ Py_DECREF (src_ref );
502
+ memset (src , 0 , sizeof (src_ref ));
503
+ }
504
+
505
+ N -- ;
506
+ dst += dst_stride ;
507
+ src += src_stride ;
508
+ }
509
+ return 0 ;
510
+ }
511
+
512
+ NPY_NO_EXPORT int
513
+ object_to_string_get_loop (PyArrayMethod_Context * context ,
514
+ int NPY_UNUSED (aligned ), int move_references ,
515
+ const npy_intp * NPY_UNUSED (strides ),
516
+ PyArrayMethod_StridedLoop * * out_loop ,
517
+ NpyAuxData * * out_transferdata ,
518
+ NPY_ARRAYMETHOD_FLAGS * flags )
519
+ {
520
+ * flags = NPY_METH_REQUIRES_PYAPI ;
521
+
522
+ /* NOTE: auxdata is only really necessary to flag `move_references` */
523
+ _object_to_string_auxdata * data = PyMem_Malloc (sizeof (* data ));
524
+ if (data == NULL ) {
525
+ return -1 ;
526
+ }
527
+ data -> base .free = & _object_to_string_auxdata_free ;
528
+ data -> base .clone = & _object_to_string_auxdata_clone ;
529
+
530
+ Py_INCREF (context -> descriptors [1 ]);
531
+ data -> descr = context -> descriptors [1 ];
532
+ data -> move_references = move_references ;
533
+ * out_transferdata = (NpyAuxData * )data ;
534
+ * out_loop = & object_to_string_strided_loop ;
535
+ return 0 ;
536
+ }
537
+
538
+ static NPY_CASTING
539
+ object_to_string_resolve_descriptors (PyArrayMethodObject * NPY_UNUSED (self ),
540
+ PyArray_DTypeMeta * dtypes [2 ],
541
+ PyArray_Descr * given_descrs [2 ],
542
+ PyArray_Descr * loop_descrs [2 ],
543
+ npy_intp * NPY_UNUSED (view_offset ))
544
+ {
545
+ if (given_descrs [1 ] == NULL ) {
546
+ loop_descrs [1 ] = (PyArray_Descr * )new_stringdtype_instance (
547
+ (PyTypeObject * )dtypes [1 ]);
548
+ if (loop_descrs [1 ] == NULL ) {
549
+ return -1 ;
550
+ }
551
+ }
552
+ else {
553
+ Py_INCREF (given_descrs [1 ]);
554
+ loop_descrs [1 ] = given_descrs [1 ];
555
+ }
556
+
557
+ Py_INCREF (given_descrs [0 ]);
558
+ loop_descrs [0 ] = given_descrs [0 ];
559
+
560
+ return NPY_SAFE_CASTING ;
561
+ }
562
+
563
+ static PyType_Slot o2s_slots [] = {
564
+ {NPY_METH_resolve_descriptors , & object_to_string_resolve_descriptors },
565
+ {_NPY_METH_get_loop , & object_to_string_get_loop },
566
+ {0 , NULL }};
567
+
568
+ static char * o2s_name = "cast_object_to_StringDType" ;
569
+
452
570
PyArrayMethod_Spec *
453
571
get_cast_spec (const char * name , NPY_CASTING casting ,
454
572
NPY_ARRAYMETHOD_FLAGS flags , PyArray_DTypeMeta * * dtypes ,
@@ -501,10 +619,10 @@ get_casts(PyArray_DTypeMeta *this, PyArray_DTypeMeta *other)
501
619
502
620
int is_pandas = (this == (PyArray_DTypeMeta * )& PandasStringDType );
503
621
504
- int num_casts = 5 ;
622
+ int num_casts = 6 ;
505
623
506
624
if (is_pandas ) {
507
- num_casts = 7 ;
625
+ num_casts = 8 ;
508
626
509
627
PyArray_DTypeMeta * * t2o_dtypes = get_dtypes (this , other );
510
628
@@ -537,6 +655,12 @@ get_casts(PyArray_DTypeMeta *this, PyArray_DTypeMeta *other)
537
655
s2b_name , NPY_UNSAFE_CASTING , NPY_METH_NO_FLOATINGPOINT_ERRORS ,
538
656
s2b_dtypes , s2b_slots );
539
657
658
+ PyArray_DTypeMeta * * o2s_dtypes = get_dtypes (& PyArray_ObjectDType , this );
659
+
660
+ PyArrayMethod_Spec * ObjectToStringCastSpec =
661
+ get_cast_spec (o2s_name , NPY_SAFE_CASTING , NPY_METH_REQUIRES_PYAPI ,
662
+ o2s_dtypes , o2s_slots );
663
+
540
664
PyArrayMethod_Spec * * casts = NULL ;
541
665
542
666
casts = malloc (num_casts * sizeof (PyArrayMethod_Spec * ));
@@ -545,13 +669,14 @@ get_casts(PyArray_DTypeMeta *this, PyArray_DTypeMeta *other)
545
669
casts [1 ] = UnicodeToStringCastSpec ;
546
670
casts [2 ] = StringToUnicodeCastSpec ;
547
671
casts [3 ] = StringToBoolCastSpec ;
672
+ casts [4 ] = ObjectToStringCastSpec ;
548
673
if (is_pandas ) {
549
- casts [4 ] = ThisToOtherCastSpec ;
550
- casts [5 ] = OtherToThisCastSpec ;
551
- casts [6 ] = NULL ;
674
+ casts [5 ] = ThisToOtherCastSpec ;
675
+ casts [6 ] = OtherToThisCastSpec ;
676
+ casts [7 ] = NULL ;
552
677
}
553
678
else {
554
- casts [4 ] = NULL ;
679
+ casts [5 ] = NULL ;
555
680
}
556
681
557
682
return casts ;
0 commit comments