summaryrefslogtreecommitdiff
path: root/numpy
diff options
context:
space:
mode:
authorEric Wieser <wieser.eric@gmail.com>2018-12-16 16:25:54 -0800
committerEric Wieser <wieser.eric@gmail.com>2018-12-16 20:26:53 -0800
commite03283dda358db50e21c4f230c0d2d9d9174a002 (patch)
treec45be72d0cad3dbc5154341408a588ad0ecd1d70 /numpy
parent129fe22dafd519229e326fca6849151f9c686807 (diff)
downloadnumpy-e03283dda358db50e21c4f230c0d2d9d9174a002.tar.gz
BUG: Ensure that arr.ctypes works on arrays with overlapping fields
These would previously fail in `from_buffer`, since these arrays cannot be used with the buffer protocol.
Diffstat (limited to 'numpy')
-rw-r--r--numpy/core/_internal.py39
-rw-r--r--numpy/core/tests/test_multiarray.py9
2 files changed, 40 insertions, 8 deletions
diff --git a/numpy/core/_internal.py b/numpy/core/_internal.py
index 4b5fda65c..a5742983c 100644
--- a/numpy/core/_internal.py
+++ b/numpy/core/_internal.py
@@ -244,21 +244,44 @@ class _missing_ctypes(object):
self.value = ptr
+class _unsafe_first_element_pointer(object):
+ """
+ Helper to allow viewing an array as a ctypes pointer to the first element
+
+ This avoids:
+ * dealing with strides
+ * `.view` rejecting object-containing arrays
+ * `memoryview` not supporting overlapping fields
+ """
+ def __init__(self, arr):
+ self.base = arr
+
+ @property
+ def __array_interface__(self):
+ i = dict(
+ shape=(),
+ typestr='|V0',
+ data=(self.base.__array_interface__['data'][0], False),
+ strides=(),
+ version=3,
+ )
+ return i
+
def _get_void_ptr(arr):
"""
Get a `ctypes.c_void_p` to arr.data, that keeps a reference to the array
"""
import numpy as np
- # don't let subclasses interfere
- arr = arr.view(ndarray)
- # collapse the array to point to at most 1 element, so it become contiguous
- arr = arr[np.s_[:1,] * arr.ndim + np.s_[...,]]
- # then convert to ctypes now that we've reduced it to a simple, empty, array
- arr.flags.writeable = True
- arr = (ctypes.c_char * 0).from_buffer(arr)
+ # convert to a 0d array that has a data pointer referrign to the start
+ # of arr. This holds a reference to arr.
+ simple_arr = np.asarray(_unsafe_first_element_pointer(arr))
+
+ # create a `char[0]` using the same memory.
+ c_arr = (ctypes.c_char * 0).from_buffer(simple_arr)
+
# finally cast to void*
- return ctypes.cast(ctypes.pointer(arr), ctypes.c_void_p)
+ return ctypes.cast(ctypes.pointer(c_arr), ctypes.c_void_p)
class _ctypes(object):
diff --git a/numpy/core/tests/test_multiarray.py b/numpy/core/tests/test_multiarray.py
index 171b2ad7f..fa21018ec 100644
--- a/numpy/core/tests/test_multiarray.py
+++ b/numpy/core/tests/test_multiarray.py
@@ -7480,6 +7480,14 @@ class TestCTypes(object):
np.array([1, 2, 3]),
np.array([['one', 'two'], ['three', 'four']]),
np.array((1, 2), dtype='i4,i4'),
+ np.zeros((2,), dtype=
+ np.dtype(dict(
+ formats=['<i4', '<i4'],
+ names=['a', 'b'],
+ offsets=[0, 2],
+ itemsize=6
+ ))
+ ),
np.array([None], dtype=object),
np.array([]),
np.empty((0, 0)),
@@ -7488,6 +7496,7 @@ class TestCTypes(object):
'1d',
'2d',
'structured',
+ 'overlapping',
'object',
'empty',
'empty-2d',