diff --git a/src/wrapper/_pvt_struct_v3.cpp b/src/wrapper/_pvt_struct_v3.cpp index dcdc83ec5ea8086db68ef58261d5183604ae97f9..61e1cf8468a396481ac0dc338a306175d2da2915 100644 --- a/src/wrapper/_pvt_struct_v3.cpp +++ b/src/wrapper/_pvt_struct_v3.cpp @@ -8,8 +8,9 @@ #include "Python.h" #include "structmember.h" #include +#include "numpy_init.hpp" -static PyTypeObject PyStructType; +// static PyTypeObject PyStructType; /* The translation function for each format character is table driven */ typedef struct _formatdef { @@ -75,7 +76,7 @@ typedef struct { char c; PY_LONG_LONG x; } s_long_long; #define LONG_LONG_ALIGN (sizeof(s_long_long) - sizeof(PY_LONG_LONG)) #endif -#ifdef HAVE_C99_BOOL +#if !defined(__cplusplus) && defined(HAVE_C99_BOOL) #define BOOL_TYPE _Bool typedef struct { char c; _Bool x; } s_bool; #define BOOL_ALIGN (sizeof(s_bool) - sizeof(BOOL_TYPE)) @@ -266,6 +267,7 @@ get_size_t(PyObject *v, size_t *p) /* Floating point helpers */ +#if 0 static PyObject * unpack_float(const char *p, /* start of 4-byte string */ @@ -291,6 +293,8 @@ unpack_double(const char *p, /* start of 8-byte string */ return PyFloat_FromDouble(x); } +#endif + /* Helper to format the range error exceptions */ static int _range_error(const formatdef *f, int is_unsigned) @@ -333,6 +337,8 @@ _range_error(const formatdef *f, int is_unsigned) TYPE is one of char, byte, ubyte, etc. */ +// {{{ + /* Native mode routines. ****************************************************/ /* NOTE: In all n[up]_ routines handling types larger than 1 byte, there is @@ -486,6 +492,24 @@ nu_double(const char *p, const formatdef *f) return PyFloat_FromDouble(x); } +static PyObject * +nu_complex_float(const char *p, const formatdef *f) +{ + float re, im; + memcpy((char *)&re, p, sizeof re); + memcpy((char *)&im, p+sizeof re, sizeof im); + return PyComplex_FromDoubles((double)re, (double) im); +} + +static PyObject * +nu_complex_double(const char *p, const formatdef *f) +{ + double re, im; + memcpy((char *)&re, p, sizeof re); + memcpy((char *)&im, p+sizeof re, sizeof im); + return PyComplex_FromDoubles(re, im); +} + static PyObject * nu_void_p(const char *p, const formatdef *f) { @@ -706,6 +730,66 @@ np_double(char *p, PyObject *v, const formatdef *f) return 0; } +static int +np_complex_float(char *p, PyObject *v, const formatdef *f) +{ + if (PyArray_IsZeroDim(v)) { + PyObject *v_cast = PyArray_Cast( + reinterpret_cast(v), + NPY_CFLOAT); + if (!v_cast) + return -1; + memcpy(p, PyArray_DATA(v_cast), PyArray_NBYTES(v_cast)); + Py_DECREF(v_cast); + } + else { + float re = 0.0f; + float im = 0.0f; + Py_complex cplx = PyComplex_AsCComplex(v); + if (PyErr_Occurred()) { + PyErr_SetString(StructError, + "required argument is not a complex"); + return -1; + } + + re = (float)cplx.real; + im = (float)cplx.imag; + memcpy(p, (char *)&re, sizeof re); + memcpy(p+sizeof re, (char *)&im, sizeof im); + } + return 0; +} + +static int +np_complex_double(char *p, PyObject *v, const formatdef *f) +{ + if (PyArray_IsZeroDim(v)) { + PyObject *v_cast = PyArray_Cast( + reinterpret_cast(v), + NPY_CDOUBLE); + if (!v_cast) + return -1; + memcpy(p, PyArray_DATA(v_cast), PyArray_NBYTES(v_cast)); + Py_DECREF(v_cast); + } + else { + double re = 0.0; + double im = 0.0; + Py_complex cplx = PyComplex_AsCComplex(v); + if (PyErr_Occurred()) { + PyErr_SetString(StructError, + "required argument is not a complex"); + return -1; + } + re = cplx.real; + im = cplx.imag; + memcpy(p, (char *)&re, sizeof re); + memcpy(p+sizeof re, (char *)&im, sizeof im); + } + return 0; +} + + static int np_void_p(char *p, PyObject *v, const formatdef *f) { @@ -745,467 +829,19 @@ static formatdef native_table[] = { {'?', sizeof(BOOL_TYPE), BOOL_ALIGN, nu_bool, np_bool}, {'f', sizeof(float), FLOAT_ALIGN, nu_float, np_float}, {'d', sizeof(double), DOUBLE_ALIGN, nu_double, np_double}, + {'F', 2*sizeof(float), FLOAT_ALIGN, nu_complex_float, np_complex_float}, + {'D', 2*sizeof(double), DOUBLE_ALIGN, nu_complex_double, np_complex_double}, {'P', sizeof(void *), VOID_P_ALIGN, nu_void_p, np_void_p}, {0} }; -/* Big-endian routines. *****************************************************/ - -static PyObject * -bu_int(const char *p, const formatdef *f) -{ - long x = 0; - Py_ssize_t i = f->size; - const unsigned char *bytes = (const unsigned char *)p; - do { - x = (x<<8) | *bytes++; - } while (--i > 0); - /* Extend the sign bit. */ - if (SIZEOF_LONG > f->size) - x |= -(x & (1L << ((8 * f->size) - 1))); - return PyLong_FromLong(x); -} - -static PyObject * -bu_uint(const char *p, const formatdef *f) -{ - unsigned long x = 0; - Py_ssize_t i = f->size; - const unsigned char *bytes = (const unsigned char *)p; - do { - x = (x<<8) | *bytes++; - } while (--i > 0); - if (x <= LONG_MAX) - return PyLong_FromLong((long)x); - return PyLong_FromUnsignedLong(x); -} - -static PyObject * -bu_longlong(const char *p, const formatdef *f) -{ -#ifdef HAVE_LONG_LONG - PY_LONG_LONG x = 0; - Py_ssize_t i = f->size; - const unsigned char *bytes = (const unsigned char *)p; - do { - x = (x<<8) | *bytes++; - } while (--i > 0); - /* Extend the sign bit. */ - if (SIZEOF_LONG_LONG > f->size) - x |= -(x & ((PY_LONG_LONG)1 << ((8 * f->size) - 1))); - if (x >= LONG_MIN && x <= LONG_MAX) - return PyLong_FromLong(Py_SAFE_DOWNCAST(x, PY_LONG_LONG, long)); - return PyLong_FromLongLong(x); -#else - return _PyLong_FromByteArray((const unsigned char *)p, - 8, - 0, /* little-endian */ - 1 /* signed */); -#endif -} - -static PyObject * -bu_ulonglong(const char *p, const formatdef *f) -{ -#ifdef HAVE_LONG_LONG - unsigned PY_LONG_LONG x = 0; - Py_ssize_t i = f->size; - const unsigned char *bytes = (const unsigned char *)p; - do { - x = (x<<8) | *bytes++; - } while (--i > 0); - if (x <= LONG_MAX) - return PyLong_FromLong(Py_SAFE_DOWNCAST(x, unsigned PY_LONG_LONG, long)); - return PyLong_FromUnsignedLongLong(x); -#else - return _PyLong_FromByteArray((const unsigned char *)p, - 8, - 0, /* little-endian */ - 0 /* signed */); -#endif -} - -static PyObject * -bu_float(const char *p, const formatdef *f) -{ - return unpack_float(p, 0); -} - -static PyObject * -bu_double(const char *p, const formatdef *f) -{ - return unpack_double(p, 0); -} - -static PyObject * -bu_bool(const char *p, const formatdef *f) -{ - char x; - memcpy((char *)&x, p, sizeof x); - return PyBool_FromLong(x != 0); -} - -static int -bp_int(char *p, PyObject *v, const formatdef *f) -{ - long x; - Py_ssize_t i; - if (get_long(v, &x) < 0) - return -1; - i = f->size; - if (i != SIZEOF_LONG) { - if ((i == 2) && (x < -32768 || x > 32767)) - RANGE_ERROR(x, f, 0, 0xffffL); -#if (SIZEOF_LONG != 4) - else if ((i == 4) && (x < -2147483648L || x > 2147483647L)) - RANGE_ERROR(x, f, 0, 0xffffffffL); -#endif - } - do { - p[--i] = (char)x; - x >>= 8; - } while (i > 0); - return 0; -} - -static int -bp_uint(char *p, PyObject *v, const formatdef *f) -{ - unsigned long x; - Py_ssize_t i; - if (get_ulong(v, &x) < 0) - return -1; - i = f->size; - if (i != SIZEOF_LONG) { - unsigned long maxint = 1; - maxint <<= (unsigned long)(i * 8); - if (x >= maxint) - RANGE_ERROR(x, f, 1, maxint - 1); - } - do { - p[--i] = (char)x; - x >>= 8; - } while (i > 0); - return 0; -} - -static int -bp_longlong(char *p, PyObject *v, const formatdef *f) -{ - int res; - v = get_pylong(v); - if (v == NULL) - return -1; - res = _PyLong_AsByteArray((PyLongObject *)v, - (unsigned char *)p, - 8, - 0, /* little_endian */ - 1 /* signed */); - Py_DECREF(v); - return res; -} - -static int -bp_ulonglong(char *p, PyObject *v, const formatdef *f) -{ - int res; - v = get_pylong(v); - if (v == NULL) - return -1; - res = _PyLong_AsByteArray((PyLongObject *)v, - (unsigned char *)p, - 8, - 0, /* little_endian */ - 0 /* signed */); - Py_DECREF(v); - return res; -} - -static int -bp_float(char *p, PyObject *v, const formatdef *f) -{ - double x = PyFloat_AsDouble(v); - if (x == -1 && PyErr_Occurred()) { - PyErr_SetString(StructError, - "required argument is not a float"); - return -1; - } - return _PyFloat_Pack4(x, (unsigned char *)p, 0); -} - -static int -bp_double(char *p, PyObject *v, const formatdef *f) -{ - double x = PyFloat_AsDouble(v); - if (x == -1 && PyErr_Occurred()) { - PyErr_SetString(StructError, - "required argument is not a float"); - return -1; - } - return _PyFloat_Pack8(x, (unsigned char *)p, 0); -} - -static int -bp_bool(char *p, PyObject *v, const formatdef *f) -{ - int y; - y = PyObject_IsTrue(v); - if (y < 0) - return -1; - *p = (char)y; - return 0; -} - -static formatdef bigendian_table[] = { - {'x', 1, 0, NULL}, - {'b', 1, 0, nu_byte, np_byte}, - {'B', 1, 0, nu_ubyte, np_ubyte}, - {'c', 1, 0, nu_char, np_char}, - {'s', 1, 0, NULL}, - {'p', 1, 0, NULL}, - {'h', 2, 0, bu_int, bp_int}, - {'H', 2, 0, bu_uint, bp_uint}, - {'i', 4, 0, bu_int, bp_int}, - {'I', 4, 0, bu_uint, bp_uint}, - {'l', 4, 0, bu_int, bp_int}, - {'L', 4, 0, bu_uint, bp_uint}, - {'q', 8, 0, bu_longlong, bp_longlong}, - {'Q', 8, 0, bu_ulonglong, bp_ulonglong}, - {'?', 1, 0, bu_bool, bp_bool}, - {'f', 4, 0, bu_float, bp_float}, - {'d', 8, 0, bu_double, bp_double}, - {0} -}; - -/* Little-endian routines. *****************************************************/ - -static PyObject * -lu_int(const char *p, const formatdef *f) -{ - long x = 0; - Py_ssize_t i = f->size; - const unsigned char *bytes = (const unsigned char *)p; - do { - x = (x<<8) | bytes[--i]; - } while (i > 0); - /* Extend the sign bit. */ - if (SIZEOF_LONG > f->size) - x |= -(x & (1L << ((8 * f->size) - 1))); - return PyLong_FromLong(x); -} - -static PyObject * -lu_uint(const char *p, const formatdef *f) -{ - unsigned long x = 0; - Py_ssize_t i = f->size; - const unsigned char *bytes = (const unsigned char *)p; - do { - x = (x<<8) | bytes[--i]; - } while (i > 0); - if (x <= LONG_MAX) - return PyLong_FromLong((long)x); - return PyLong_FromUnsignedLong((long)x); -} - -static PyObject * -lu_longlong(const char *p, const formatdef *f) -{ -#ifdef HAVE_LONG_LONG - PY_LONG_LONG x = 0; - Py_ssize_t i = f->size; - const unsigned char *bytes = (const unsigned char *)p; - do { - x = (x<<8) | bytes[--i]; - } while (i > 0); - /* Extend the sign bit. */ - if (SIZEOF_LONG_LONG > f->size) - x |= -(x & ((PY_LONG_LONG)1 << ((8 * f->size) - 1))); - if (x >= LONG_MIN && x <= LONG_MAX) - return PyLong_FromLong(Py_SAFE_DOWNCAST(x, PY_LONG_LONG, long)); - return PyLong_FromLongLong(x); -#else - return _PyLong_FromByteArray((const unsigned char *)p, - 8, - 1, /* little-endian */ - 1 /* signed */); -#endif -} - -static PyObject * -lu_ulonglong(const char *p, const formatdef *f) -{ -#ifdef HAVE_LONG_LONG - unsigned PY_LONG_LONG x = 0; - Py_ssize_t i = f->size; - const unsigned char *bytes = (const unsigned char *)p; - do { - x = (x<<8) | bytes[--i]; - } while (i > 0); - if (x <= LONG_MAX) - return PyLong_FromLong(Py_SAFE_DOWNCAST(x, unsigned PY_LONG_LONG, long)); - return PyLong_FromUnsignedLongLong(x); -#else - return _PyLong_FromByteArray((const unsigned char *)p, - 8, - 1, /* little-endian */ - 0 /* signed */); -#endif -} - -static PyObject * -lu_float(const char *p, const formatdef *f) -{ - return unpack_float(p, 1); -} - -static PyObject * -lu_double(const char *p, const formatdef *f) -{ - return unpack_double(p, 1); -} - -static int -lp_int(char *p, PyObject *v, const formatdef *f) -{ - long x; - Py_ssize_t i; - if (get_long(v, &x) < 0) - return -1; - i = f->size; - if (i != SIZEOF_LONG) { - if ((i == 2) && (x < -32768 || x > 32767)) - RANGE_ERROR(x, f, 0, 0xffffL); -#if (SIZEOF_LONG != 4) - else if ((i == 4) && (x < -2147483648L || x > 2147483647L)) - RANGE_ERROR(x, f, 0, 0xffffffffL); -#endif - } - do { - *p++ = (char)x; - x >>= 8; - } while (--i > 0); - return 0; -} - -static int -lp_uint(char *p, PyObject *v, const formatdef *f) -{ - unsigned long x; - Py_ssize_t i; - if (get_ulong(v, &x) < 0) - return -1; - i = f->size; - if (i != SIZEOF_LONG) { - unsigned long maxint = 1; - maxint <<= (unsigned long)(i * 8); - if (x >= maxint) - RANGE_ERROR(x, f, 1, maxint - 1); - } - do { - *p++ = (char)x; - x >>= 8; - } while (--i > 0); - return 0; -} - -static int -lp_longlong(char *p, PyObject *v, const formatdef *f) -{ - int res; - v = get_pylong(v); - if (v == NULL) - return -1; - res = _PyLong_AsByteArray((PyLongObject*)v, - (unsigned char *)p, - 8, - 1, /* little_endian */ - 1 /* signed */); - Py_DECREF(v); - return res; -} - -static int -lp_ulonglong(char *p, PyObject *v, const formatdef *f) -{ - int res; - v = get_pylong(v); - if (v == NULL) - return -1; - res = _PyLong_AsByteArray((PyLongObject*)v, - (unsigned char *)p, - 8, - 1, /* little_endian */ - 0 /* signed */); - Py_DECREF(v); - return res; -} - -static int -lp_float(char *p, PyObject *v, const formatdef *f) -{ - double x = PyFloat_AsDouble(v); - if (x == -1 && PyErr_Occurred()) { - PyErr_SetString(StructError, - "required argument is not a float"); - return -1; - } - return _PyFloat_Pack4(x, (unsigned char *)p, 1); -} - -static int -lp_double(char *p, PyObject *v, const formatdef *f) -{ - double x = PyFloat_AsDouble(v); - if (x == -1 && PyErr_Occurred()) { - PyErr_SetString(StructError, - "required argument is not a float"); - return -1; - } - return _PyFloat_Pack8(x, (unsigned char *)p, 1); -} - -static formatdef lilendian_table[] = { - {'x', 1, 0, NULL}, - {'b', 1, 0, nu_byte, np_byte}, - {'B', 1, 0, nu_ubyte, np_ubyte}, - {'c', 1, 0, nu_char, np_char}, - {'s', 1, 0, NULL}, - {'p', 1, 0, NULL}, - {'h', 2, 0, lu_int, lp_int}, - {'H', 2, 0, lu_uint, lp_uint}, - {'i', 4, 0, lu_int, lp_int}, - {'I', 4, 0, lu_uint, lp_uint}, - {'l', 4, 0, lu_int, lp_int}, - {'L', 4, 0, lu_uint, lp_uint}, - {'q', 8, 0, lu_longlong, lp_longlong}, - {'Q', 8, 0, lu_ulonglong, lp_ulonglong}, - {'?', 1, 0, bu_bool, bp_bool}, /* Std rep not endian dep, - but potentially different from native rep -- reuse bx_bool funcs. */ - {'f', 4, 0, lu_float, lp_float}, - {'d', 8, 0, lu_double, lp_double}, - {0} -}; - +// }}} static const formatdef * whichtable(char **pfmt) { const char *fmt = (*pfmt)++; /* May be backed out of later */ switch (*fmt) { - case '<': - return lilendian_table; - case '>': - case '!': /* Network byte order is big-endian */ - return bigendian_table; - case '=': { /* Host byte order -- different from native in alignment! */ - int n = 1; - char *p = (char *) &n; - if (*p == 1) - return lilendian_table; - else - return bigendian_table; - } default: --*pfmt; /* Back out of pointer increment */ /* Fall through */ @@ -1323,7 +959,7 @@ prepare_s(PyStructObject *self) self->s_size = size; self->s_len = len; - codes = PyMem_MALLOC((len + 1) * sizeof(formatcode)); + codes = (formatcode *) PyMem_MALLOC((len + 1) * sizeof(formatcode)); if (codes == NULL) { PyErr_NoMemory(); return -1; @@ -1510,7 +1146,7 @@ s_unpack(PyObject *self, PyObject *input) PyBuffer_Release(&vbuf); return NULL; } - result = s_unpack_internal(soself, vbuf.buf); + result = s_unpack_internal(soself, (char *) vbuf.buf); PyBuffer_Release(&vbuf); return result; } @@ -2060,8 +1696,9 @@ static struct PyModuleDef _structmodule = { NULL }; +extern "C" PyMODINIT_FUNC -PyInit__struct(void) +PyInit__pvt_struct(void) { PyObject *m; @@ -2073,45 +1710,6 @@ PyInit__struct(void) if (PyType_Ready(&PyStructType) < 0) return NULL; - /* Check endian and swap in faster functions */ - { - int one = 1; - formatdef *native = native_table; - formatdef *other, *ptr; - if ((int)*(unsigned char*)&one) - other = lilendian_table; - else - other = bigendian_table; - /* Scan through the native table, find a matching - entry in the endian table and swap in the - native implementations whenever possible - (64-bit platforms may not have "standard" sizes) */ - while (native->format != '\0' && other->format != '\0') { - ptr = other; - while (ptr->format != '\0') { - if (ptr->format == native->format) { - /* Match faster when formats are - listed in the same order */ - if (ptr == other) - other++; - /* Only use the trick if the - size matches */ - if (ptr->size != native->size) - break; - /* Skip float and double, could be - "unknown" float format */ - if (ptr->format == 'd' || ptr->format == 'f') - break; - ptr->pack = native->pack; - ptr->unpack = native->unpack; - break; - } - ptr++; - } - native++; - } - } - /* Add some symbolic constants to the module */ if (StructError == NULL) { StructError = PyErr_NewException("struct.error", NULL, NULL); @@ -2127,3 +1725,5 @@ PyInit__struct(void) return m; } + +// vim: fdm=marker diff --git a/test/test_array.py b/test/test_array.py index c12ba43ba78aa5273b75b948fae694911d329ecb..05c28814b5c70afa1f16d754ee214e84a42d82d5 100644 --- a/test/test_array.py +++ b/test/test_array.py @@ -60,7 +60,7 @@ def test_absrealimag(ctx_factory): n = 111 for func in [abs, real, imag, conj]: for dtype in [np.int32, np.float32, np.complex64]: - print func, dtype + print(func, dtype) a = -make_random_array(queue, dtype, n) host_res = func(a.get()) @@ -68,9 +68,9 @@ def test_absrealimag(ctx_factory): correct = np.allclose(dev_res, host_res) if not correct: - print dev_res - print host_res - print dev_res-host_res + print(dev_res) + print(host_res) + print(dev_res-host_res) assert correct @@ -127,8 +127,8 @@ def test_mix_complex(ctx_factory): (np.float64, np.complex128), ]) - from operator import add, mul, sub, div - for op in [add, sub, mul, div, pow]: + from operator import add, mul, sub, truediv + for op in [add, sub, mul, truediv, pow]: for dtype_a0, dtype_b0 in dtypes: for dtype_a, dtype_b in [ (dtype_a0, dtype_b0), @@ -153,7 +153,7 @@ def test_mix_complex(ctx_factory): ary_b = make_random_array(queue, dtype_b, size) host_ary_b = ary_b.get() - print op, dtype_a, dtype_b, is_scalar_a, is_scalar_b + print(op, dtype_a, dtype_b, is_scalar_a, is_scalar_b) dev_result = op(ary_a, ary_b).get() host_result = op(host_ary_a, host_ary_b) @@ -162,18 +162,18 @@ def test_mix_complex(ctx_factory): # served a Python complex that is really a # smaller numpy complex. - print "HOST_DTYPE: %s DEV_DTYPE: %s" % ( - host_result.dtype, dev_result.dtype) + print("HOST_DTYPE: %s DEV_DTYPE: %s" % ( + host_result.dtype, dev_result.dtype)) dev_result = dev_result.astype(host_result.dtype) err = la.norm(host_result-dev_result)/la.norm(host_result) - print err + print(err) correct = err < 1e-5 if not correct: - print host_result - print dev_result - print host_result - dev_result + print(host_result) + print(dev_result) + print(host_result - dev_result) assert correct @@ -735,7 +735,7 @@ def test_scan(ctx_factory): is_ok = (dev_data.get() == desired_result).all() if not is_ok: - print summarize_error(dev_data.get(), desired_result, host_data) + print(summarize_error(dev_data.get(), desired_result, host_data)) assert is_ok from gc import collect diff --git a/test/test_clmath.py b/test/test_clmath.py index 68ca381cff53bbae6ab46d962ac56acb64f7cdba..3864138034073a85e2dc48240142b45fd8bd761c 100644 --- a/test/test_clmath.py +++ b/test/test_clmath.py @@ -203,7 +203,7 @@ def test_bessel_j(ctx_factory): scipy_bessel = spec.jn(n, a) error = np.max(np.abs(cl_bessel-scipy_bessel)) - print n, error + print(n, error) assert error < 1e-10 assert not np.isnan(cl_bessel).any()