File dp_complex.h¶
File List > doppler > dp_complex.h
Go to the documentation of this file
#ifndef DP_COMPLEX_H
#define DP_COMPLEX_H
#if defined(_MSC_VER) && !defined(__clang__)
#error "doppler requires C99 _Complex; on Windows build with clang-cl, not cl.exe"
#endif
#ifdef _WIN32
#include <math.h>
#include <complex.h> /* first, so it is never included after: see above */
/* The UCRT's <math.h> hijacks the identifier `complex`.
*
* `corecrt_math.h` carries `#define complex _complex` -- a legacy alias for
* its `struct _complex`, the argument type of the old `_cabs`. C99 spells a
* complex type `float complex`, which doppler writes in 196 places, and under
* that macro each one becomes `float _complex`: a struct, not a complex
* number, reported as `error: redefinition of '_complex'` a line later.
*
* On POSIX `<complex.h>` is what defines `complex` as `_Complex`, and the
* UCRT's does not -- so the C99 meaning has to be restored explicitly, after
* <math.h> has had its say. Found by the Windows runner;
* no amount of Linux CI can see it, because no POSIX libc does this. */
#ifdef complex
#undef complex
#endif
#define complex _Complex
/* Not the UCRT's struct-typed functions: see the file comment. These are
clang builtins, so they lower to register moves rather than calls. */
#undef crealf
#undef cimagf
#undef conjf
#undef creal
#undef cimag
#undef conj
#define crealf __builtin_crealf
#define cimagf __builtin_cimagf
#define conjf __builtin_conjf
#define creal __builtin_creal
#define cimag __builtin_cimag
#define conj __builtin_conj
/* The UCRT's <complex.h> defines both as a `_Fcomplex` struct built by
`_FCbuild`, which no arithmetic operator accepts. */
#undef I
#undef _Complex_I
#define I (__extension__ 1.0fi)
/* `_Complex_I` is reserved to the implementation, and on this path that is
exactly what this header is standing in for: it supplies the C99 surface
the platform's <complex.h> does not, so defining the name C99 requires that
header to define is the correct thing rather than an intrusion. Two benchmarks spell it. */
/* NOLINTNEXTLINE(bugprone-reserved-identifier,cert-dcl37-c) */
#define _Complex_I I
static inline float
dp_cabsf (float _Complex z)
{
return hypotf (__builtin_crealf (z), __builtin_cimagf (z));
}
static inline float
dp_cargf (float _Complex z)
{
return atan2f (__builtin_cimagf (z), __builtin_crealf (z));
}
static inline float _Complex
dp_cexpf (float _Complex z)
{
float e = expf (__builtin_crealf (z));
float im = __builtin_cimagf (z);
return __builtin_complex (e * cosf (im), e * sinf (im));
}
static inline double
dp_cabs (double _Complex z)
{
return hypot (__builtin_creal (z), __builtin_cimag (z));
}
static inline double
dp_carg (double _Complex z)
{
return atan2 (__builtin_cimag (z), __builtin_creal (z));
}
static inline double _Complex
dp_cexp (double _Complex z)
{
double e = exp (__builtin_creal (z));
double im = __builtin_cimag (z);
return __builtin_complex (e * cos (im), e * sin (im));
}
/* The C99 names, pointed at the definitions above. A macro rather than the
name itself because the UCRT has already declared that name, taking a
struct, and C has no overloading. */
#define cabsf dp_cabsf
#define cargf dp_cargf
#define cexpf dp_cexpf
#define cabs dp_cabs
#define carg dp_carg
#define cexp dp_cexp
#else /* POSIX: the platform header, unchanged. */
#include <complex.h>
#endif /* _WIN32 */
#endif /* DP_COMPLEX_H */