xref: /petsc/include/petsccxxcomplexfix.h (revision a17a2c17395fd5f30b5a762bb0dbf7d722de50da)
1 #pragma once
2 
3 /* MANSEC = Sys */
4 
5 /*
6     The pragma below silence all compiler warnings coming from code in this header file.
7     In particular, it silences `-Wfloat-equal` warnings in `operator==()` and `operator!=` below.
8     Other compilers beyond GCC support this pragma.
9 */
10 #if defined(__GNUC__) && (__GNUC__ >= 4) && !defined(__NEC__)
11   #pragma GCC system_header
12 #endif
13 
14 /*
15      Defines additional operator overloading for the C++ complex class that are "missing" in the standard
16      include files. For example, the code fragment
17 
18      std::complex<double> c = 22.0;
19      c = 11 + c;
20 
21      will produce a compile time error such as
22 
23      error: no match for 'operator+' (operand types are 'int' and 'std::complex<double>')
24 
25      The code fragment
26 
27      std::complex<float> c = 22.0;
28      c = 11.0 + c;
29 
30      will produce a compile time error such as
31 
32      error: no match for 'operator+' (operand types are 'double' and 'std::complex<float>')
33 
34      This deficiency means one may need to write cumbersome code while working with the C++ complex classes.
35 
36      This include file defines a few additional operator overload methods for the C++ complex classes to handle
37      these cases naturally within PETSc code.
38 
39      This file is included in petscsystypes.h when feasible. In the small number of cases where these additional methods
40      may conflict with other code one may add '#define PETSC_SKIP_CXX_COMPLEX_FIX 1' before including any PETSc include
41      files to prevent these methods from being provided.
42 */
43 
44 // In PETSc, a quad precision PetscComplex is a C type even with clanguage=cxx, therefore no C++ operator overloading needed for it.
45 #if !defined(PETSC_USE_REAL___FLOAT128)
46   #include <type_traits>
47 // For operations "Atype op Cmplex" or "Cmplex op Atype" with Cmplex being PetscComplex, the built-in support allows Atype to be PetscComplex or PetscReal.
48 // We extend Atype to other C++ arithmetic types, and __fp16, __float128 if available.
49 // We put Cmplex as a template parameter so that we can enforce Cmplex to be PetscComplex and forbid compilers to convert other types to PetscComplex.
50 // This requires C++11 or later.
51 template <typename Cmplex, typename Atype> // operation on a complex and an arithmetic type
52 struct petsccomplex_extended_type :
53   std::integral_constant<bool, (std::is_same<Cmplex, PetscComplex>::value && std::is_arithmetic<Atype>::value && !std::is_same<Atype, PetscReal>::value)
54   #if defined(PETSC_HAVE_REAL___FP16) && !defined(PETSC_USE_REAL___FP16)
55                                  || std::is_same<Atype, __fp16>::value
56   #endif
57   #if defined(PETSC_HAVE_REAL___FLOAT128) && !defined(PETSC_USE_REAL___FLOAT128)
58                                  || std::is_same<Atype, __float128>::value
59   #endif
60                          > {
61 };
62 
63 template <typename Cmplex, typename Atype>
64 inline typename std::enable_if<petsccomplex_extended_type<Cmplex, Atype>::value, Cmplex>::type operator+(const Atype &lhs, const Cmplex &rhs)
65 {
66   return PetscReal(lhs) + rhs;
67 }
68 
69 template <typename Cmplex, typename Atype>
70 inline typename std::enable_if<petsccomplex_extended_type<Cmplex, Atype>::value, Cmplex>::type operator+(const Cmplex &lhs, const Atype &rhs)
71 {
72   return lhs + PetscReal(rhs);
73 }
74 
75 template <typename Cmplex, typename Atype>
76 inline typename std::enable_if<petsccomplex_extended_type<Cmplex, Atype>::value, Cmplex>::type operator-(const Atype &lhs, const Cmplex &rhs)
77 {
78   return PetscReal(lhs) - rhs;
79 }
80 
81 template <typename Cmplex, typename Atype>
82 inline typename std::enable_if<petsccomplex_extended_type<Cmplex, Atype>::value, Cmplex>::type operator-(const Cmplex &lhs, const Atype &rhs)
83 {
84   return lhs - PetscReal(rhs);
85 }
86 
87 template <typename Cmplex, typename Atype>
88 inline typename std::enable_if<petsccomplex_extended_type<Cmplex, Atype>::value, Cmplex>::type operator*(const Atype &lhs, const Cmplex &rhs)
89 {
90   return PetscReal(lhs) * rhs;
91 }
92 
93 template <typename Cmplex, typename Atype>
94 inline typename std::enable_if<petsccomplex_extended_type<Cmplex, Atype>::value, Cmplex>::type operator*(const Cmplex &lhs, const Atype &rhs)
95 {
96   return lhs * PetscReal(rhs);
97 }
98 
99 template <typename Cmplex, typename Atype>
100 inline typename std::enable_if<petsccomplex_extended_type<Cmplex, Atype>::value, Cmplex>::type operator/(const Atype &lhs, const Cmplex &rhs)
101 {
102   return PetscReal(lhs) / rhs;
103 }
104 
105 template <typename Cmplex, typename Atype>
106 inline typename std::enable_if<petsccomplex_extended_type<Cmplex, Atype>::value, Cmplex>::type operator/(const Cmplex &lhs, const Atype &rhs)
107 {
108   return lhs / PetscReal(rhs);
109 }
110 
111 template <typename Cmplex, typename Atype>
112 inline typename std::enable_if<petsccomplex_extended_type<Cmplex, Atype>::value, bool>::type operator==(const Atype &lhs, const Cmplex &rhs)
113 {
114   return rhs.imag() == PetscReal(0) && rhs.real() == PetscReal(lhs);
115 }
116 
117 template <typename Cmplex, typename Atype>
118 inline typename std::enable_if<petsccomplex_extended_type<Cmplex, Atype>::value, bool>::type operator==(const Cmplex &lhs, const Atype &rhs)
119 {
120   return lhs.imag() == PetscReal(0) && lhs.real() == PetscReal(rhs);
121 }
122 
123 template <typename Cmplex, typename Atype>
124 inline typename std::enable_if<petsccomplex_extended_type<Cmplex, Atype>::value, bool>::type operator!=(const Atype &lhs, const Cmplex &rhs)
125 {
126   return rhs.imag() != PetscReal(0) || rhs.real() != PetscReal(lhs);
127 }
128 
129 template <typename Cmplex, typename Atype>
130 inline typename std::enable_if<petsccomplex_extended_type<Cmplex, Atype>::value, bool>::type operator!=(const Cmplex &lhs, const Atype &rhs)
131 {
132   return lhs.imag() != PetscReal(0) || lhs.real() != PetscReal(rhs);
133 }
134 
135 #endif
136