1
1
#include "casts.h"
2
2
3
- // And now the actual cast code! Starting with the "resolver" which tells
4
- // us about cast safety.
5
- // Note also the `view_offset`! It is a way for you to tell NumPy, that this
6
- // cast does not require anything at all, but the cast can simply be done as
7
- // a view.
8
- // For `arr.astype()` it might mean returning a view (eventually, not yet).
9
- // For ufuncs, it already means that they don't have to do a cast at all!
10
- //
11
- // From https://numpy.org/neps/nep-0043-extensible-ufuncs.html#arraymethod:
12
- // resolve_descriptors returns the safety of the operation (casting safety)
13
3
static NPY_CASTING
14
4
string_to_string_resolve_descriptors (PyObject * NPY_UNUSED (self ),
15
5
PyArray_DTypeMeta * NPY_UNUSED (dtypes [2 ]),
16
6
PyArray_Descr * given_descrs [2 ],
17
7
PyArray_Descr * loop_descrs [2 ],
18
- npy_intp * view_offset )
8
+ npy_intp * NPY_UNUSED ( view_offset ) )
19
9
{
20
10
Py_INCREF (given_descrs [0 ]);
21
11
loop_descrs [0 ] = given_descrs [0 ];
@@ -33,28 +23,32 @@ string_to_string_resolve_descriptors(PyObject *NPY_UNUSED(self),
33
23
}
34
24
35
25
static int
36
- string_to_string (PyArrayMethod_Context * NPY_UNUSED ( context ) ,
37
- char * * const data [], npy_intp const dimensions [],
38
- npy_intp const strides [], NpyAuxData * NPY_UNUSED (auxdata ))
26
+ string_to_string (PyArrayMethod_Context * context , char * const data [] ,
27
+ npy_intp const dimensions [], npy_intp const strides [],
28
+ NpyAuxData * NPY_UNUSED (auxdata ))
39
29
{
40
30
npy_intp N = dimensions [0 ];
41
- char * * in = data [0 ];
42
- char * * out = data [1 ];
43
- npy_intp in_stride = strides [0 ];
44
- npy_intp out_stride = strides [1 ];
31
+ char * * in = (char * * )data [0 ];
32
+ char * * out = (char * * )data [1 ];
33
+ // strides are in bytes but pointer offsets are in pointer widths, so
34
+ // divide by the element size (one pointer width) to get the pointer offset
35
+ npy_intp in_stride = strides [0 ] / context -> descriptors [0 ]-> elsize ;
36
+ npy_intp out_stride = strides [1 ] / context -> descriptors [1 ]-> elsize ;
45
37
46
38
while (N -- ) {
47
- strcpy (* out , * in );
39
+ size_t length = strlen (* in );
40
+ out [0 ] = (char * )malloc ((sizeof (char ) * length ) + 1 );
41
+ strncpy (* out , * in , length + 1 );
48
42
in += in_stride ;
49
43
out += out_stride ;
50
44
}
51
45
52
46
return 0 ;
53
47
}
54
48
55
- static PyArray_DTypeMeta * a2a_dtypes [2 ] = {NULL , NULL };
49
+ static PyArray_DTypeMeta * s2s_dtypes [2 ] = {NULL , NULL };
56
50
57
- static PyType_Slot a2a_slots [] = {
51
+ static PyType_Slot s2s_slots [] = {
58
52
{NPY_METH_resolve_descriptors , & string_to_string_resolve_descriptors },
59
53
{NPY_METH_strided_loop , & string_to_string },
60
54
{NPY_METH_unaligned_strided_loop , & string_to_string },
@@ -66,8 +60,8 @@ PyArrayMethod_Spec StringToStringCastSpec = {
66
60
.nout = 1 ,
67
61
.casting = NPY_UNSAFE_CASTING ,
68
62
.flags = NPY_METH_SUPPORTS_UNALIGNED ,
69
- .dtypes = a2a_dtypes ,
70
- .slots = a2a_slots ,
63
+ .dtypes = s2s_dtypes ,
64
+ .slots = s2s_slots ,
71
65
};
72
66
73
67
PyArrayMethod_Spec * *
0 commit comments