summaryrefslogtreecommitdiff
path: root/numpy
diff options
context:
space:
mode:
authorAllan Haldane <allan.haldane@gmail.com>2017-06-28 16:08:30 -0400
committerAllan Haldane <allan.haldane@gmail.com>2018-09-27 15:43:54 -0400
commit27d4ce926b7166c9e7fe88f7b64f8636cb464ee3 (patch)
treeec4d1e624ae9575e2e636d0dd1ff51fc0229cfea /numpy
parentb76c0dfbf9eec3bd3ac6ec2fc7b507bee8f3c0e1 (diff)
downloadnumpy-27d4ce926b7166c9e7fe88f7b64f8636cb464ee3.tar.gz
ENH: Implement methods for uint-alignment
Implements IsAligned, IsUintAligned, npy_uint_alignment
Diffstat (limited to 'numpy')
-rw-r--r--numpy/core/src/common/array_assign.c17
-rw-r--r--numpy/core/src/common/array_assign.h14
-rw-r--r--numpy/core/src/multiarray/common.c44
-rw-r--r--numpy/core/src/multiarray/common.h44
-rw-r--r--numpy/core/src/multiarray/flagsobject.c3
-rw-r--r--numpy/core/src/multiarray/lowlevel_strided_loops.c.src11
-rw-r--r--numpy/core/src/multiarray/methods.c7
7 files changed, 78 insertions, 62 deletions
diff --git a/numpy/core/src/common/array_assign.c b/numpy/core/src/common/array_assign.c
index e4cb651d6..ac3fdbef7 100644
--- a/numpy/core/src/common/array_assign.c
+++ b/numpy/core/src/common/array_assign.c
@@ -130,6 +130,23 @@ raw_array_is_aligned(int ndim, npy_intp *shape,
}
}
+NPY_NO_EXPORT int
+IsAligned(PyArrayObject *ap)
+{
+ return raw_array_is_aligned(PyArray_NDIM(ap), PyArray_DIMS(ap),
+ PyArray_DATA(ap), PyArray_STRIDES(ap),
+ PyArray_DESCR(ap)->alignment);
+}
+
+NPY_NO_EXPORT int
+IsUintAligned(PyArrayObject *ap)
+{
+ return raw_array_is_aligned(PyArray_NDIM(ap), PyArray_DIMS(ap),
+ PyArray_DATA(ap), PyArray_STRIDES(ap),
+ npy_uint_alignment(PyArray_DESCR(ap)->elsize));
+}
+
+
/* Returns 1 if the arrays have overlapping data, 0 otherwise */
NPY_NO_EXPORT int
diff --git a/numpy/core/src/common/array_assign.h b/numpy/core/src/common/array_assign.h
index fdc36d3a2..07438c5e8 100644
--- a/numpy/core/src/common/array_assign.h
+++ b/numpy/core/src/common/array_assign.h
@@ -94,6 +94,20 @@ NPY_NO_EXPORT int
raw_array_is_aligned(int ndim, npy_intp *shape,
char *data, npy_intp *strides, int alignment);
+/*
+ * Checks if an array is aligned to its "true alignment"
+ * given by dtype->alignment.
+ */
+NPY_NO_EXPORT int
+IsAligned(PyArrayObject *ap);
+
+/*
+ * Checks if an array is aligned to its "uint alignment"
+ * given by npy_uint_alignment(dtype->elsize).
+ */
+NPY_NO_EXPORT int
+IsUintAligned(PyArrayObject *ap);
+
/* Returns 1 if the arrays have overlapping data, 0 otherwise */
NPY_NO_EXPORT int
arrays_overlap(PyArrayObject *arr1, PyArrayObject *arr2);
diff --git a/numpy/core/src/multiarray/common.c b/numpy/core/src/multiarray/common.c
index 4f695fdc7..5b4611e8a 100644
--- a/numpy/core/src/multiarray/common.c
+++ b/numpy/core/src/multiarray/common.c
@@ -587,50 +587,6 @@ _zerofill(PyArrayObject *ret)
return 0;
}
-NPY_NO_EXPORT int
-_IsAligned(PyArrayObject *ap)
-{
- int i;
- npy_uintp aligned;
- npy_uintp alignment = PyArray_DESCR(ap)->alignment;
-
- /* alignment 1 types should have a efficient alignment for copy loops */
- if (PyArray_ISFLEXIBLE(ap) || PyArray_ISSTRING(ap)) {
- 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) {
- return 1;
- }
- aligned = (npy_uintp)PyArray_DATA(ap);
-
- for (i = 0; i < PyArray_NDIM(ap); i++) {
-#if NPY_RELAXED_STRIDES_CHECKING
- /* skip dim == 1 as it is not required to have stride 0 */
- if (PyArray_DIM(ap, i) > 1) {
- /* if shape[i] == 1, the stride is never used */
- aligned |= (npy_uintp)PyArray_STRIDES(ap)[i];
- }
- else if (PyArray_DIM(ap, i) == 0) {
- /* an array with zero elements is always aligned */
- return 1;
- }
-#else /* not NPY_RELAXED_STRIDES_CHECKING */
- aligned |= (npy_uintp)PyArray_STRIDES(ap)[i];
-#endif /* not NPY_RELAXED_STRIDES_CHECKING */
- }
- return npy_is_aligned((void *)aligned, alignment);
-}
-
NPY_NO_EXPORT npy_bool
_IsWriteable(PyArrayObject *ap)
{
diff --git a/numpy/core/src/multiarray/common.h b/numpy/core/src/multiarray/common.h
index db0a49920..13876f17b 100644
--- a/numpy/core/src/multiarray/common.h
+++ b/numpy/core/src/multiarray/common.h
@@ -1,5 +1,6 @@
#ifndef _NPY_PRIVATE_COMMON_H_
#define _NPY_PRIVATE_COMMON_H_
+#include "structmember.h"
#include <numpy/npy_common.h>
#include <numpy/npy_cpu.h>
#include <numpy/ndarraytypes.h>
@@ -56,9 +57,6 @@ index2ptr(PyArrayObject *mp, npy_intp i);
NPY_NO_EXPORT int
_zerofill(PyArrayObject *ret);
-NPY_NO_EXPORT int
-_IsAligned(PyArrayObject *ap);
-
NPY_NO_EXPORT npy_bool
_IsWriteable(PyArrayObject *ap);
@@ -182,6 +180,15 @@ check_and_adjust_axis(int *axis, int ndim)
return check_and_adjust_axis_msg(axis, ndim, Py_None);
}
+/* used for some alignment checks */
+#define _ALIGN(type) offsetof(struct {char c; type v;}, v)
+/*
+ * Disable harmless compiler warning "4116: unnamed type definition in
+ * parentheses" which is caused by the _ALIGN macro.
+ */
+#if defined(_MSC_VER)
+#pragma warning(disable:4116)
+#endif
/*
* return true if pointer is aligned to 'alignment'
@@ -201,6 +208,37 @@ npy_is_aligned(const void * p, const npy_uintp alignment)
}
}
+/* Get equivalent "uint" alignment given an itemsize, for use in copy code */
+static NPY_INLINE int
+npy_uint_alignment(int itemsize)
+{
+ npy_uintp alignment = 0; /* return value of 0 means unaligned */
+
+ switch(itemsize){
+ case 1:
+ return 1;
+ case 2:
+ alignment = _ALIGN(npy_uint16);
+ break;
+ case 4:
+ alignment = _ALIGN(npy_uint32);
+ break;
+ case 8:
+ alignment = _ALIGN(npy_uint64);
+ break;
+ case 16:
+ /*
+ * 16 byte types are copied using 2 uint64 assignments.
+ * See the strided copy function in lowlevel_strided_loops.c.
+ */
+ alignment = _ALIGN(npy_uint64);
+ break;
+ default:
+ }
+
+ return alignment;
+}
+
/*
* memchr with stride and invert argument
* intended for small searches where a call out to libc memchr is costly.
diff --git a/numpy/core/src/multiarray/flagsobject.c b/numpy/core/src/multiarray/flagsobject.c
index a78bedccb..85ea49fb4 100644
--- a/numpy/core/src/multiarray/flagsobject.c
+++ b/numpy/core/src/multiarray/flagsobject.c
@@ -12,6 +12,7 @@
#include "npy_config.h"
#include "npy_pycompat.h"
+#include "array_assign.h"
#include "common.h"
@@ -64,7 +65,7 @@ PyArray_UpdateFlags(PyArrayObject *ret, int flagmask)
_UpdateContiguousFlags(ret);
}
if (flagmask & NPY_ARRAY_ALIGNED) {
- if (_IsAligned(ret)) {
+ if (IsAligned(ret)) {
PyArray_ENABLEFLAGS(ret, NPY_ARRAY_ALIGNED);
}
else {
diff --git a/numpy/core/src/multiarray/lowlevel_strided_loops.c.src b/numpy/core/src/multiarray/lowlevel_strided_loops.c.src
index b25b4a8b6..51b1a273d 100644
--- a/numpy/core/src/multiarray/lowlevel_strided_loops.c.src
+++ b/numpy/core/src/multiarray/lowlevel_strided_loops.c.src
@@ -10,7 +10,6 @@
#define PY_SSIZE_T_CLEAN
#include "Python.h"
-#include "structmember.h"
#define NPY_NO_DEPRECATED_API NPY_API_VERSION
#define _MULTIARRAYMODULE
@@ -20,16 +19,6 @@
#include "lowlevel_strided_loops.h"
-/* used for some alignment checks */
-#define _ALIGN(type) offsetof(struct {char c; type v;}, v)
-/*
- * Disable harmless compiler warning "4116: unnamed type definition in
- * parentheses" which is caused by the _ALIGN macro.
- */
-#if defined(_MSC_VER)
-#pragma warning(disable:4116)
-#endif
-
/*
* x86 platform works with unaligned access but the compiler is allowed to
diff --git a/numpy/core/src/multiarray/methods.c b/numpy/core/src/multiarray/methods.c
index 6317d6a16..cb63c7f74 100644
--- a/numpy/core/src/multiarray/methods.c
+++ b/numpy/core/src/multiarray/methods.c
@@ -21,6 +21,7 @@
#include "conversion_utils.h"
#include "shape.h"
#include "strfuncs.h"
+#include "array_assign.h"
#include "methods.h"
#include "alloc.h"
@@ -1785,11 +1786,11 @@ array_setstate(PyArrayObject *self, PyObject *args)
fa->data = datastr;
#ifndef NPY_PY3K
/* Check that the string is not interned */
- if (!_IsAligned(self) || swap || PyString_CHECK_INTERNED(rawdata)) {
+ if (!IsAligned(self) || swap || PyString_CHECK_INTERNED(rawdata)) {
#else
/* Bytes should always be considered immutable, but we just grab the
* pointer if they are large, to save memory. */
- if (!_IsAligned(self) || swap || (len <= 1000)) {
+ if (!IsAligned(self) || swap || (len <= 1000)) {
#endif
npy_intp num = PyArray_NBYTES(self);
fa->data = PyDataMem_NEW(num);
@@ -2281,7 +2282,7 @@ array_setflags(PyArrayObject *self, PyObject *args, PyObject *kwds)
if (PyObject_Not(align_flag)) {
PyArray_CLEARFLAGS(self, NPY_ARRAY_ALIGNED);
}
- else if (_IsAligned(self)) {
+ else if (IsAligned(self)) {
PyArray_ENABLEFLAGS(self, NPY_ARRAY_ALIGNED);
}
else {