mirror of
https://github.com/python/cpython.git
synced 2025-08-30 21:48:47 +00:00
gh-61103: Support double complex (_Complex) type in ctypes (#120894)
Example: ```pycon >>> import ctypes >>> ctypes.__STDC_IEC_559_COMPLEX__ 1 >>> libm = ctypes.CDLL('libm.so.6') >>> libm.clog.argtypes = [ctypes.c_double_complex] >>> libm.clog.restype = ctypes.c_double_complex >>> libm.clog(1+1j) (0.34657359027997264+0.7853981633974483j) ``` Co-authored-by: Nice Zombies <nineteendo19d0@gmail.com> Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com> Co-authored-by: Victor Stinner <vstinner@python.org>
This commit is contained in:
parent
a0b8b342c5
commit
6988ff02a5
17 changed files with 316 additions and 17 deletions
34
Modules/_complex.h
Normal file
34
Modules/_complex.h
Normal file
|
@ -0,0 +1,34 @@
|
|||
/* Workarounds for buggy complex number arithmetic implementations. */
|
||||
|
||||
#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
|
|
@ -1750,7 +1750,11 @@ class _ctypes.c_void_p "PyObject *" "clinic_state_sub()->PyCSimpleType_Type"
|
|||
[clinic start generated code]*/
|
||||
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=dd4d9646c56f43a9]*/
|
||||
|
||||
#if defined(Py_HAVE_C_COMPLEX) && defined(FFI_TARGET_HAS_COMPLEX_TYPE)
|
||||
static const char SIMPLE_TYPE_CHARS[] = "cbBhHiIlLdCfuzZqQPXOv?g";
|
||||
#else
|
||||
static const char SIMPLE_TYPE_CHARS[] = "cbBhHiIlLdfuzZqQPXOv?g";
|
||||
#endif
|
||||
|
||||
/*[clinic input]
|
||||
_ctypes.c_wchar_p.from_param as c_wchar_p_from_param
|
||||
|
@ -2226,7 +2230,17 @@ PyCSimpleType_init(PyObject *self, PyObject *args, PyObject *kwds)
|
|||
goto error;
|
||||
}
|
||||
|
||||
stginfo->ffi_type_pointer = *fmt->pffi_type;
|
||||
if (!fmt->pffi_type->elements) {
|
||||
stginfo->ffi_type_pointer = *fmt->pffi_type;
|
||||
}
|
||||
else {
|
||||
stginfo->ffi_type_pointer.size = fmt->pffi_type->size;
|
||||
stginfo->ffi_type_pointer.alignment = fmt->pffi_type->alignment;
|
||||
stginfo->ffi_type_pointer.type = fmt->pffi_type->type;
|
||||
stginfo->ffi_type_pointer.elements = PyMem_Malloc(2 * sizeof(ffi_type));
|
||||
memcpy(stginfo->ffi_type_pointer.elements,
|
||||
fmt->pffi_type->elements, 2 * sizeof(ffi_type));
|
||||
}
|
||||
stginfo->align = fmt->pffi_type->alignment;
|
||||
stginfo->length = 0;
|
||||
stginfo->size = fmt->pffi_type->size;
|
||||
|
|
|
@ -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
|
||||
#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);
|
||||
|
|
|
@ -105,6 +105,10 @@ module _ctypes
|
|||
#include "pycore_global_objects.h"// _Py_ID()
|
||||
#include "pycore_traceback.h" // _PyTraceback_Add()
|
||||
|
||||
#if defined(Py_HAVE_C_COMPLEX) && defined(FFI_TARGET_HAS_COMPLEX_TYPE)
|
||||
#include "../_complex.h" // complex
|
||||
#endif
|
||||
|
||||
#include "clinic/callproc.c.h"
|
||||
|
||||
#define CTYPES_CAPSULE_NAME_PYMEM "_ctypes pymem"
|
||||
|
@ -651,6 +655,9 @@ union result {
|
|||
double d;
|
||||
float f;
|
||||
void *p;
|
||||
#if defined(Py_HAVE_C_COMPLEX) && defined(FFI_TARGET_HAS_COMPLEX_TYPE)
|
||||
double complex C;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct argument {
|
||||
|
|
|
@ -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()) {
|
||||
return NULL;
|
||||
}
|
||||
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;
|
||||
|
|
|
@ -2,9 +2,15 @@
|
|||
# include <alloca.h>
|
||||
#endif
|
||||
|
||||
#include <ffi.h> // FFI_TARGET_HAS_COMPLEX_TYPE
|
||||
|
||||
#include "pycore_moduleobject.h" // _PyModule_GetState()
|
||||
#include "pycore_typeobject.h" // _PyType_GetModuleState()
|
||||
|
||||
#if defined(Py_HAVE_C_COMPLEX) && defined(FFI_TARGET_HAS_COMPLEX_TYPE)
|
||||
# include "../_complex.h" // complex
|
||||
#endif
|
||||
|
||||
#ifndef MS_WIN32
|
||||
#define max(a, b) ((a) > (b) ? (a) : (b))
|
||||
#define min(a, b) ((a) < (b) ? (a) : (b))
|
||||
|
@ -393,6 +399,9 @@ struct tagPyCArgObject {
|
|||
double d;
|
||||
float f;
|
||||
void *p;
|
||||
#if defined(Py_HAVE_C_COMPLEX) && defined(FFI_TARGET_HAS_COMPLEX_TYPE)
|
||||
double complex C;
|
||||
#endif
|
||||
} value;
|
||||
PyObject *obj;
|
||||
Py_ssize_t size; /* for the 'V' tag */
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue