Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
- Notifications
You must be signed in to change notification settings - Fork 35.2k
gh-61103: support double complex (_Complex) type in ctypes#120894
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Uh oh!
There was an error while loading. Please reload this page.
Changes from all commits
c9b872fb402300ad39e6dfd9135bc296fb37453ca5e444c9c2e9064332ffacf9163950bf81682af2fdce6d9d5abf9c709cccd418deb313dc693c04e0ee7049de91bbeb79200ebe6a68504e89c20bc87da6347412e757fb61eb989cb44aae22153608af42aa8e57198e36732bc892b241ee953c3875cbb8f8e3a47f4479197b1c3662ea028a837add41b8f37e0bd1ebe6eba445a6ac463615e8def7d99733d170bd4dd044c4cf7045264fa7df54b96423db2005a7e366388e2cae88856556b524ce9cab4a6d5bf66File filter
Filter by extension
Conversations
Uh oh!
There was an error while loading. Please reload this page.
Jump to
Uh oh!
There was an error while loading. Please reload this page.
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -205,6 +205,12 @@ class c_longdouble(_SimpleCData): | ||
| if sizeof(c_longdouble) == sizeof(c_double): | ||
| c_longdouble = c_double | ||
| try: | ||
| class c_double_complex(_SimpleCData): | ||
| _type_ = "C" | ||
skirpichev marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| except AttributeError: | ||
| pass | ||
| if _calcsize("l") == _calcsize("q"): | ||
| # if long and long long have the same size, make c_longlong an alias for c_long | ||
| c_longlong = c_long | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,4 @@ | ||
| import ctypes | ||
| import math | ||
| import unittest | ||
| from ctypes import (CDLL, CFUNCTYPE, POINTER, create_string_buffer, sizeof, | ||
| @@ -21,6 +22,17 @@ def test_sqrt(self): | ||
| self.assertEqual(lib.my_sqrt(4.0), 2.0) | ||
| self.assertEqual(lib.my_sqrt(2.0), math.sqrt(2.0)) | ||
| @unittest.skipUnless(hasattr(ctypes, "c_double_complex"), | ||
| "requires C11 complex type") | ||
| def test_csqrt(self): | ||
| lib.my_csqrt.argtypes = ctypes.c_double_complex, | ||
| lib.my_csqrt.restype = ctypes.c_double_complex | ||
| self.assertEqual(lib.my_csqrt(4), 2+0j) | ||
| self.assertAlmostEqual(lib.my_csqrt(-1+0.01j), | ||
skirpichev marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| 0.004999937502734214+1.0000124996093955j) | ||
| self.assertAlmostEqual(lib.my_csqrt(-1-0.01j), | ||
| 0.004999937502734214-1.0000124996093955j) | ||
| def test_qsort(self): | ||
| comparefunc = CFUNCTYPE(c_int, POINTER(c_char), POINTER(c_char)) | ||
| lib.my_qsort.argtypes = c_void_p, c_size_t, c_size_t, comparefunc | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| Support :c:expr:`double complex` C type in :mod:`ctypes` via | ||
| :class:`~ctypes.c_double_complex` if compiler has C11 complex | ||
| arithmetic. Patch by Sergey B Kirpichev. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,34 @@ | ||
| /* Workarounds for buggy complex number arithmetic implementations. */ | ||
vstinner marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| #ifndef Py_HAVE_C_COMPLEX | ||
| # error "this header file should only be included if Py_HAVE_C_COMPLEX is defined" | ||
| #endif | ||
| #include <complex.h> | ||
| /* Other compilers (than clang), that claims to | ||
| implement C11 *and* define __STDC_IEC_559_COMPLEX__ - don't have | ||
| issue with CMPLX(). This is specific to glibc & clang combination: | ||
| https://sourceware.org/bugzilla/show_bug.cgi?id=26287 | ||
| Here we fallback to using __builtin_complex(), available in clang | ||
| v12+. Else CMPLX implemented following C11 6.2.5p13: "Each complex type | ||
| has the same representation and alignment requirements as an array | ||
| type containing exactly two elements of the corresponding real type; | ||
| the first element is equal to the real part, and the second element | ||
| to the imaginary part, of the complex number. | ||
| */ | ||
| #if !defined(CMPLX) | ||
| # if defined(__clang__) && __has_builtin(__builtin_complex) | ||
| # define CMPLX(x, y) __builtin_complex ((double) (x), (double) (y)) | ||
| # else | ||
| static inline double complex | ||
| CMPLX(double real, double imag) | ||
| { | ||
| double complex z; | ||
| ((double *)(&z))[0] = real; | ||
| ((double *)(&z))[1] = imag; | ||
| return z; | ||
| } | ||
| # endif | ||
| #endif | ||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -13,6 +13,12 @@ | ||||||
| #include <Python.h> | ||||||
| #include <ffi.h> // FFI_TARGET_HAS_COMPLEX_TYPE | ||||||
| #if defined(Py_HAVE_C_COMPLEX) && defined(FFI_TARGET_HAS_COMPLEX_TYPE) | ||||||
| # include "../_complex.h" // csqrt() | ||||||
| # undef I // for _ctypes_test_generated.c.h | ||||||
vstinner marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. Member There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
| ||||||
| #endif | ||||||
| #include <stdio.h> // printf() | ||||||
| #include <stdlib.h> // qsort() | ||||||
| #include <string.h> // memset() | ||||||
| @@ -443,6 +449,13 @@ EXPORT(double) my_sqrt(double a) | ||||||
| return sqrt(a); | ||||||
| } | ||||||
| #if defined(Py_HAVE_C_COMPLEX) && defined(FFI_TARGET_HAS_COMPLEX_TYPE) | ||||||
| EXPORT(double complex) my_csqrt(double complex a) | ||||||
| { | ||||||
| return csqrt(a); | ||||||
| } | ||||||
| #endif | ||||||
| EXPORT(void) my_qsort(void *base, size_t num, size_t width, int(*compare)(const void*, const void*)) | ||||||
| { | ||||||
| qsort(base, num, width, compare); | ||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -14,6 +14,9 @@ | ||
| #include <ffi.h> | ||
| #include "ctypes.h" | ||
| #if defined(Py_HAVE_C_COMPLEX) && defined(FFI_TARGET_HAS_COMPLEX_TYPE) | ||
| # include "../_complex.h" // complex | ||
| #endif | ||
| #define CTYPES_CFIELD_CAPSULE_NAME_PYMEM "_ctypes/cfield.c pymem" | ||
| @@ -1087,6 +1090,30 @@ d_get(void *ptr, Py_ssize_t size) | ||
| return PyFloat_FromDouble(val); | ||
| } | ||
| #if defined(Py_HAVE_C_COMPLEX) && defined(FFI_TARGET_HAS_COMPLEX_TYPE) | ||
| static PyObject * | ||
| C_set(void *ptr, PyObject *value, Py_ssize_t size) | ||
| { | ||
| Py_complex c = PyComplex_AsCComplex(value); | ||
| if (c.real == -1 && PyErr_Occurred()) { | ||
skirpichev marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| return NULL; | ||
| } | ||
skirpichev marked this conversation as resolved.
Uh oh!There was an error while loading. Please reload this page. | ||
| double complex x = CMPLX(c.real, c.imag); | ||
| memcpy(ptr, &x, sizeof(x)); | ||
| _RET(value); | ||
| } | ||
| static PyObject * | ||
| C_get(void *ptr, Py_ssize_t size) | ||
| { | ||
| double complex x; | ||
| memcpy(&x, ptr, sizeof(x)); | ||
| return PyComplex_FromDoubles(creal(x), cimag(x)); | ||
| } | ||
| #endif | ||
| static PyObject * | ||
| d_set_sw(void *ptr, PyObject *value, Py_ssize_t size) | ||
| { | ||
| @@ -1592,6 +1619,9 @@ static struct fielddesc formattable[] = { | ||
| { 'B', B_set, B_get, NULL}, | ||
| { 'c', c_set, c_get, NULL}, | ||
| { 'd', d_set, d_get, NULL, d_set_sw, d_get_sw}, | ||
| #if defined(Py_HAVE_C_COMPLEX) && defined(FFI_TARGET_HAS_COMPLEX_TYPE) | ||
| { 'C', C_set, C_get, NULL}, | ||
| #endif | ||
| { 'g', g_set, g_get, NULL}, | ||
| { 'f', f_set, f_get, NULL, f_set_sw, f_get_sw}, | ||
| { 'h', h_set, h_get, NULL, h_set_sw, h_get_sw}, | ||
| @@ -1642,6 +1672,9 @@ _ctypes_init_fielddesc(void) | ||
| case 'B': fd->pffi_type = &ffi_type_uchar; break; | ||
| case 'c': fd->pffi_type = &ffi_type_schar; break; | ||
| case 'd': fd->pffi_type = &ffi_type_double; break; | ||
| #if defined(Py_HAVE_C_COMPLEX) && defined(FFI_TARGET_HAS_COMPLEX_TYPE) | ||
| case 'C': fd->pffi_type = &ffi_type_complex_double; break; | ||
| #endif | ||
| case 'g': fd->pffi_type = &ffi_type_longdouble; break; | ||
| case 'f': fd->pffi_type = &ffi_type_float; break; | ||
| case 'h': fd->pffi_type = &ffi_type_sshort; break; | ||
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.