Skip to content

Commit 5ad9a75

Browse files
Merge pull request #23 from ngoldbaum/cast-fixes
Make string to string casts a copy
2 parents 4648ca5 + cc27bee commit 5ad9a75

File tree

1 file changed

+17
-23
lines changed

1 file changed

+17
-23
lines changed

stringdtype/stringdtype/src/casts.c

Lines changed: 17 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,11 @@
11
#include "casts.h"
22

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)
133
static NPY_CASTING
144
string_to_string_resolve_descriptors(PyObject *NPY_UNUSED(self),
155
PyArray_DTypeMeta *NPY_UNUSED(dtypes[2]),
166
PyArray_Descr *given_descrs[2],
177
PyArray_Descr *loop_descrs[2],
18-
npy_intp *view_offset)
8+
npy_intp *NPY_UNUSED(view_offset))
199
{
2010
Py_INCREF(given_descrs[0]);
2111
loop_descrs[0] = given_descrs[0];
@@ -33,28 +23,32 @@ string_to_string_resolve_descriptors(PyObject *NPY_UNUSED(self),
3323
}
3424

3525
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))
3929
{
4030
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;
4537

4638
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);
4842
in += in_stride;
4943
out += out_stride;
5044
}
5145

5246
return 0;
5347
}
5448

55-
static PyArray_DTypeMeta *a2a_dtypes[2] = {NULL, NULL};
49+
static PyArray_DTypeMeta *s2s_dtypes[2] = {NULL, NULL};
5650

57-
static PyType_Slot a2a_slots[] = {
51+
static PyType_Slot s2s_slots[] = {
5852
{NPY_METH_resolve_descriptors, &string_to_string_resolve_descriptors},
5953
{NPY_METH_strided_loop, &string_to_string},
6054
{NPY_METH_unaligned_strided_loop, &string_to_string},
@@ -66,8 +60,8 @@ PyArrayMethod_Spec StringToStringCastSpec = {
6660
.nout = 1,
6761
.casting = NPY_UNSAFE_CASTING,
6862
.flags = NPY_METH_SUPPORTS_UNALIGNED,
69-
.dtypes = a2a_dtypes,
70-
.slots = a2a_slots,
63+
.dtypes = s2s_dtypes,
64+
.slots = s2s_slots,
7165
};
7266

7367
PyArrayMethod_Spec **

0 commit comments

Comments
 (0)