Skip to content

Commit

Permalink
Workaround for numpy/numpy#9049
Browse files Browse the repository at this point in the history
This moves the ^ in the format string (to specify unaligned) to
outside the `T{}` where it is sure to be parsed correctly. This is not
strictly necessary yet, but it paves the way for pybind#832.
  • Loading branch information
bmerry committed May 4, 2017
1 parent fb8a4ed commit 271f380
Show file tree
Hide file tree
Showing 2 changed files with 16 additions and 15 deletions.
11 changes: 6 additions & 5 deletions include/pybind11/numpy.h
Original file line number Diff line number Diff line change
Expand Up @@ -991,14 +991,15 @@ inline PYBIND11_NOINLINE void register_structured_dtype(
[](const field_descriptor &a, const field_descriptor &b) { return a.offset < b.offset; });
size_t offset = 0;
std::ostringstream oss;
oss << "T{";
// mark the structure as unaligned with '^', because numpy and C++ don't
// always agree about alignment (particularly for complex), and we're
// explicitly listing all our padding. This depends on none of the fields
// overriding the endianness. Putting the ^ in front of individual fields
// isn't guaranteed to work due to https://github.com/numpy/numpy/issues/9049
oss << "^T{";
for (auto& field : ordered_fields) {
if (field.offset > offset)
oss << (field.offset - offset) << 'x';
// mark all fields with '^' (unaligned native type), because numpy
// and C++ don't always agree about alignment (particularly for
// complex, and we're explicitly listing all padding.
oss << '^';
oss << field.format << ':' << field.name << ':';
offset = field.offset + field.size;
}
Expand Down
20 changes: 10 additions & 10 deletions tests/test_numpy_dtypes.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,22 +72,22 @@ def test_format_descriptors():
assert re.match('^NumPy type info missing for .*UnboundStruct.*$', str(excinfo.value))

ld = np.dtype('longdouble')
ldbl_fmt = ('4x' if ld.alignment > 4 else '') + '^' + ld.char
ss_fmt = "T{^?:bool_:3x^I:uint_:^f:float_:" + ldbl_fmt + ":ldbl_:}"
ldbl_fmt = ('4x' if ld.alignment > 4 else '') + ld.char
ss_fmt = "^T{?:bool_:3xI:uint_:f:float_:" + ldbl_fmt + ":ldbl_:}"
dbl = np.dtype('double')
partial_fmt = ("T{^?:bool_:3x^I:uint_:^f:float_:" +
partial_fmt = ("^T{?:bool_:3xI:uint_:f:float_:" +
str(4 * (dbl.alignment > 4) + dbl.itemsize + 8 * (ld.alignment > 8)) +
"x^g:ldbl_:}")
"xg:ldbl_:}")
nested_extra = str(max(8, ld.alignment))
assert print_format_descriptors() == [
ss_fmt,
"T{^?:bool_:^I:uint_:^f:float_:^g:ldbl_:}",
"T{^" + ss_fmt + ":a:^T{^?:bool_:^I:uint_:^f:float_:^g:ldbl_:}:b:}",
"^T{?:bool_:I:uint_:f:float_:g:ldbl_:}",
"^T{" + ss_fmt + ":a:^T{?:bool_:I:uint_:f:float_:g:ldbl_:}:b:}",
partial_fmt,
"T{" + nested_extra + "x^" + partial_fmt + ":a:" + nested_extra + "x}",
"T{^3s:a:^3s:b:}",
'T{^q:e1:^B:e2:}',
'T{^Zf:cflt:^Zd:cdbl:}'
"^T{" + nested_extra + "x" + partial_fmt + ":a:" + nested_extra + "x}",
"^T{3s:a:3s:b:}",
'^T{q:e1:B:e2:}',
'^T{Zf:cflt:Zd:cdbl:}'
]


Expand Down

0 comments on commit 271f380

Please sign in to comment.