@@ -633,6 +633,67 @@ string_partition_index_loop(PyArrayMethod_Context *context,
633
633
}
634
634
635
635
636
+ template <ENCODING enc>
637
+ static int
638
+ string_slice_loop (PyArrayMethod_Context *context,
639
+ char *const data[], npy_intp const dimensions[],
640
+ npy_intp const strides[], NpyAuxData *NPY_UNUSED (auxdata))
641
+ {
642
+ int insize = context->descriptors [0 ]->elsize ;
643
+ int outsize = context->descriptors [4 ]->elsize ;
644
+
645
+ char *in_ptr = data[0 ];
646
+ char *start_ptr = data[1 ];
647
+ char *stop_ptr = data[2 ];
648
+ char *step_ptr = data[3 ];
649
+ char *out_ptr = data[4 ];
650
+
651
+ npy_intp N = dimensions[0 ];
652
+
653
+ while (N--) {
654
+ Buffer<enc> inbuf (in_ptr, insize);
655
+ Buffer<enc> outbuf (out_ptr, outsize);
656
+
657
+ // get the slice
658
+ npy_intp start = *(npy_intp*)start_ptr;
659
+ npy_intp stop = *(npy_intp*)stop_ptr;
660
+ npy_intp step = *(npy_intp*)step_ptr;
661
+
662
+ // adjust slice to string length in codepoints
663
+ // and handle negative indices
664
+ size_t num_codepoints = inbuf.num_codepoints ();
665
+ npy_intp slice_length = PySlice_AdjustIndices (num_codepoints, &start, &stop, step);
666
+
667
+ // iterate over slice and copy each character of the string
668
+ inbuf.advance_chars_or_bytes (start);
669
+ for (npy_intp i = 0 ; i < slice_length; i++) {
670
+ // copy one codepoint
671
+ inbuf.buffer_memcpy (outbuf, 1 );
672
+
673
+ // Move in inbuf by step.
674
+ inbuf += step;
675
+
676
+ // Move in outbuf by the number of chars or bytes written
677
+ outbuf.advance_chars_or_bytes (1 );
678
+ }
679
+
680
+ // fill remaining outbuf with zero bytes
681
+ for (char *tmp = outbuf.buf ; tmp < outbuf.after ; tmp++) {
682
+ *tmp = 0 ;
683
+ }
684
+
685
+ // Go to the next array element
686
+ in_ptr += strides[0 ];
687
+ start_ptr += strides[1 ];
688
+ stop_ptr += strides[2 ];
689
+ step_ptr += strides[3 ];
690
+ out_ptr += strides[4 ];
691
+ }
692
+
693
+ return 0 ;
694
+ }
695
+
696
+
636
697
/* Resolve descriptors & promoter functions */
637
698
638
699
static NPY_CASTING
@@ -1064,6 +1125,53 @@ string_partition_resolve_descriptors(
1064
1125
}
1065
1126
1066
1127
1128
+ static int
1129
+ string_slice_promoter (PyObject *NPY_UNUSED (ufunc),
1130
+ PyArray_DTypeMeta *const op_dtypes[], PyArray_DTypeMeta *const signature[],
1131
+ PyArray_DTypeMeta *new_op_dtypes[])
1132
+ {
1133
+ Py_INCREF (op_dtypes[0 ]);
1134
+ new_op_dtypes[0 ] = op_dtypes[0 ];
1135
+ new_op_dtypes[1 ] = NPY_DT_NewRef (&PyArray_IntpDType);
1136
+ new_op_dtypes[2 ] = NPY_DT_NewRef (&PyArray_IntpDType);
1137
+ new_op_dtypes[3 ] = NPY_DT_NewRef (&PyArray_IntpDType);
1138
+ Py_INCREF (op_dtypes[0 ]);
1139
+ new_op_dtypes[4 ] = op_dtypes[0 ];
1140
+ return 0 ;
1141
+ }
1142
+
1143
+ static NPY_CASTING
1144
+ string_slice_resolve_descriptors (
1145
+ PyArrayMethodObject *self,
1146
+ PyArray_DTypeMeta *const NPY_UNUSED (dtypes[5 ]),
1147
+ PyArray_Descr *const given_descrs[5],
1148
+ PyArray_Descr *loop_descrs[5],
1149
+ npy_intp *NPY_UNUSED(view_offset))
1150
+ {
1151
+ if (given_descrs[4 ]) {
1152
+ PyErr_Format (PyExc_TypeError,
1153
+ " The '%s' ufunc does not "
1154
+ " currently support the 'out' keyword" ,
1155
+ self->name );
1156
+ return _NPY_ERROR_OCCURRED_IN_CAST;
1157
+ }
1158
+
1159
+ for (int i = 0 ; i < 4 ; i++) {
1160
+ loop_descrs[i] = NPY_DT_CALL_ensure_canonical (given_descrs[i]);
1161
+ if (loop_descrs[i] == NULL ) {
1162
+ return _NPY_ERROR_OCCURRED_IN_CAST;
1163
+ }
1164
+ }
1165
+
1166
+ loop_descrs[4 ] = PyArray_DescrNew (loop_descrs[0 ]);
1167
+ if (loop_descrs[4 ] == NULL ) {
1168
+ return _NPY_ERROR_OCCURRED_IN_CAST;
1169
+ }
1170
+ loop_descrs[4 ]->elsize = loop_descrs[0 ]->elsize ;
1171
+
1172
+ return NPY_NO_CASTING;
1173
+ }
1174
+
1067
1175
/*
1068
1176
* Machinery to add the string loops to the existing ufuncs.
1069
1177
*/
@@ -1744,6 +1852,28 @@ init_string_ufuncs(PyObject *umath)
1744
1852
}
1745
1853
}
1746
1854
1855
+ dtypes[0 ] = NPY_OBJECT;
1856
+ dtypes[1 ] = NPY_INTP;
1857
+ dtypes[2 ] = NPY_INTP;
1858
+ dtypes[3 ] = NPY_INTP;
1859
+ dtypes[4 ] = NPY_OBJECT;
1860
+ if (init_ufunc (
1861
+ umath, " _slice" , 4 , 1 , dtypes, ENCODING::ASCII,
1862
+ string_slice_loop<ENCODING::ASCII>,
1863
+ string_slice_resolve_descriptors, NULL ) < 0 ) {
1864
+ return -1 ;
1865
+ }
1866
+ if (init_ufunc (
1867
+ umath, " _slice" , 4 , 1 , dtypes, ENCODING::UTF32,
1868
+ string_slice_loop<ENCODING::UTF32>,
1869
+ string_slice_resolve_descriptors, NULL ) < 0 ) {
1870
+ return -1 ;
1871
+ }
1872
+ if (init_promoter (umath, " _slice" , 4 , 1 ,
1873
+ string_slice_promoter) < 0 ) {
1874
+ return -1 ;
1875
+ }
1876
+
1747
1877
return 0 ;
1748
1878
}
1749
1879
0 commit comments