diff options
author | Allan Haldane <allan.haldane@gmail.com> | 2015-10-25 23:29:06 -0400 |
---|---|---|
committer | Allan Haldane <allan.haldane@gmail.com> | 2015-10-26 23:11:44 -0400 |
commit | 796a5f87c11fdc3a345fca5448b27a02856c2e4d (patch) | |
tree | 299afca403df6e8e37a9d59577c5263021bec855 /numpy/core/_internal.py | |
parent | 086d42d8b315cacf04ccaf4a805dc2fc7c137fee (diff) | |
download | numpy-796a5f87c11fdc3a345fca5448b27a02856c2e4d.tar.gz |
BUG: revert view safety checks
Because of slowdowns caused by the view safety checks introduced in
#5548 they are removed here for 1.10. The plan is to reintroduce
a better version of the checks in 1.11.
Diffstat (limited to 'numpy/core/_internal.py')
-rw-r--r-- | numpy/core/_internal.py | 137 |
1 files changed, 13 insertions, 124 deletions
diff --git a/numpy/core/_internal.py b/numpy/core/_internal.py index 3ddc2c64d..47c933411 100644 --- a/numpy/core/_internal.py +++ b/numpy/core/_internal.py @@ -306,94 +306,6 @@ def _copy_fields(ary): 'formats': [dt.fields[name][0] for name in dt.names]} return array(ary, dtype=copy_dtype, copy=True) -def _get_all_field_offsets(dtype, base_offset=0): - """ Returns the types and offsets of all fields in a (possibly structured) - data type, including nested fields and subarrays. - - Parameters - ---------- - dtype : data-type - Data type to extract fields from. - base_offset : int, optional - Additional offset to add to all field offsets. - - Returns - ------- - fields : list of (data-type, int) pairs - A flat list of (dtype, byte offset) pairs. - - """ - fields = [] - if dtype.fields is not None: - for name in dtype.names: - sub_dtype = dtype.fields[name][0] - sub_offset = dtype.fields[name][1] + base_offset - fields.extend(_get_all_field_offsets(sub_dtype, sub_offset)) - else: - if dtype.shape: - sub_offsets = _get_all_field_offsets(dtype.base, base_offset) - count = 1 - for dim in dtype.shape: - count *= dim - fields.extend((typ, off + dtype.base.itemsize*j) - for j in range(count) for (typ, off) in sub_offsets) - else: - fields.append((dtype, base_offset)) - return fields - -def _check_field_overlap(new_fields, old_fields): - """ Perform object memory overlap tests for two data-types (see - _view_is_safe). - - This function checks that new fields only access memory contained in old - fields, and that non-object fields are not interpreted as objects and vice - versa. - - Parameters - ---------- - new_fields : list of (data-type, int) pairs - Flat list of (dtype, byte offset) pairs for the new data type, as - returned by _get_all_field_offsets. - old_fields: list of (data-type, int) pairs - Flat list of (dtype, byte offset) pairs for the old data type, as - returned by _get_all_field_offsets. - - Raises - ------ - TypeError - If the new fields are incompatible with the old fields - - """ - - #first go byte by byte and check we do not access bytes not in old_fields - new_bytes = set() - for tp, off in new_fields: - new_bytes.update(set(range(off, off+tp.itemsize))) - old_bytes = set() - for tp, off in old_fields: - old_bytes.update(set(range(off, off+tp.itemsize))) - if new_bytes.difference(old_bytes): - raise TypeError("view would access data parent array doesn't own") - - #next check that we do not interpret non-Objects as Objects, and vv - obj_offsets = [off for (tp, off) in old_fields if tp.type is object_] - obj_size = dtype(object_).itemsize - - for fld_dtype, fld_offset in new_fields: - if fld_dtype.type is object_: - # check we do not create object views where - # there are no objects. - if fld_offset not in obj_offsets: - raise TypeError("cannot view non-Object data as Object type") - else: - # next check we do not create non-object views - # where there are already objects. - # see validate_object_field_overlap for a similar computation. - for obj_offset in obj_offsets: - if (fld_offset < obj_offset + obj_size and - obj_offset < fld_offset + fld_dtype.itemsize): - raise TypeError("cannot view Object as non-Object type") - def _getfield_is_safe(oldtype, newtype, offset): """ Checks safety of getfield for object arrays. @@ -415,10 +327,16 @@ def _getfield_is_safe(oldtype, newtype, offset): If the field access is invalid """ - new_fields = _get_all_field_offsets(newtype, offset) - old_fields = _get_all_field_offsets(oldtype) - # raises if there is a problem - _check_field_overlap(new_fields, old_fields) + if newtype.hasobject or oldtype.hasobject: + if offset == 0 and newtype == oldtype: + return + if oldtype.names: + for name in oldtype.names: + if (oldtype.fields[name][1] == offset and + oldtype.fields[name][0] == newtype): + return + raise TypeError("Cannot get/set field of an object array") + return def _view_is_safe(oldtype, newtype): """ Checks safety of a view involving object arrays, for example when @@ -426,13 +344,6 @@ def _view_is_safe(oldtype, newtype): np.zeros(10, dtype=oldtype).view(newtype) - We need to check that - 1) No memory that is not an object will be interpreted as a object, - 2) No memory containing an object will be interpreted as an arbitrary type. - Both cases can cause segfaults, eg in the case the view is written to. - Strategy here is to also disallow views where newtype has any field in a - place oldtype doesn't. - Parameters ---------- oldtype : data-type @@ -452,31 +363,9 @@ def _view_is_safe(oldtype, newtype): if oldtype == newtype: return - new_fields = _get_all_field_offsets(newtype) - new_size = newtype.itemsize - - old_fields = _get_all_field_offsets(oldtype) - old_size = oldtype.itemsize - - # if the itemsizes are not equal, we need to check that all the - # 'tiled positions' of the object match up. Here, we allow - # for arbirary itemsizes (even those possibly disallowed - # due to stride/data length issues). - if old_size == new_size: - new_num = old_num = 1 - else: - gcd_new_old = _gcd(new_size, old_size) - new_num = old_size // gcd_new_old - old_num = new_size // gcd_new_old - - # get position of fields within the tiling - new_fieldtile = [(tp, off + new_size*j) - for j in range(new_num) for (tp, off) in new_fields] - old_fieldtile = [(tp, off + old_size*j) - for j in range(old_num) for (tp, off) in old_fields] - - # raises if there is a problem - _check_field_overlap(new_fieldtile, old_fieldtile) + if newtype.hasobject or oldtype.hasobject: + raise TypeError("Cannot change data-type for object array.") + return # Given a string containing a PEP 3118 format specifier, # construct a Numpy dtype |