diff options
author | Julian Taylor <jtaylor.debian@googlemail.com> | 2014-11-26 21:51:05 +0100 |
---|---|---|
committer | Charles Harris <charlesr.harris@gmail.com> | 2015-01-21 19:06:24 -0700 |
commit | e0ef28b22a04d1d470e381f1b0cee56aec4349ed (patch) | |
tree | 369c14c41429f99c26b4006864991e205c89d722 | |
parent | c9075faa59f823033dca449edce002a0a569a9a5 (diff) | |
download | numpy-e0ef28b22a04d1d470e381f1b0cee56aec4349ed.tar.gz |
BUG: fix string arrays not being aligned
If itemsize is a power of two use that as the required alignment up to
the maximum provided by the platform. Power of two sizes may be accessed
via larger moves than bytes.
Non-power of two sizes are accessed bytewise and can thus always be
considered aligned.
Closes gh-5293
-rw-r--r-- | numpy/core/src/multiarray/common.c | 11 | ||||
-rw-r--r-- | numpy/core/tests/test_multiarray.py | 11 |
2 files changed, 21 insertions, 1 deletions
diff --git a/numpy/core/src/multiarray/common.c b/numpy/core/src/multiarray/common.c index 7015b3961..a8490f0e8 100644 --- a/numpy/core/src/multiarray/common.c +++ b/numpy/core/src/multiarray/common.c @@ -684,7 +684,16 @@ _IsAligned(PyArrayObject *ap) /* alignment 1 types should have a efficient alignment for copy loops */ if (PyArray_ISFLEXIBLE(ap) || PyArray_ISSTRING(ap)) { - alignment = NPY_MAX_COPY_ALIGNMENT; + npy_intp itemsize = PyArray_ITEMSIZE(ap); + /* power of two sizes may be loaded in larger moves */ + if (((itemsize & (itemsize - 1)) == 0)) { + alignment = itemsize > NPY_MAX_COPY_ALIGNMENT ? + NPY_MAX_COPY_ALIGNMENT : itemsize; + } + else { + /* if not power of two it will be accessed bytewise */ + alignment = 1; + } } if (alignment == 1) { diff --git a/numpy/core/tests/test_multiarray.py b/numpy/core/tests/test_multiarray.py index d472a9569..a9762978b 100644 --- a/numpy/core/tests/test_multiarray.py +++ b/numpy/core/tests/test_multiarray.py @@ -68,6 +68,17 @@ class TestFlags(TestCase): assert_equal(self.a.flags.aligned, True) assert_equal(self.a.flags.updateifcopy, False) + def test_string_align(self): + a = np.zeros(4, dtype=np.dtype('|S4')) + assert_(a.flags.aligned) + # not power of two are accessed bytewise and thus considered aligned + a = np.zeros(5, dtype=np.dtype('|S4')) + assert_(a.flags.aligned) + + def test_void_align(self): + a = np.zeros(4, dtype=np.dtype([("a", "i4"), ("b", "i4")])) + assert_(a.flags.aligned) + class TestHash(TestCase): # see #3793 def test_int(self): |