Actual source code: petsccxxcomplexfix.h

      1: #pragma once

      3: /* MANSEC = Sys */

      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

     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

     18:      std::complex<double> c = 22.0;
     19:      c = 11 + c;

     21:      will produce a compile time error such as

     23:      error: no match for 'operator+' (operand types are 'int' and 'std::complex<double>')

     25:      The code fragment

     27:      std::complex<float> c = 22.0;
     28:      c = 11.0 + c;

     30:      will produce a compile time error such as

     32:      error: no match for 'operator+' (operand types are 'double' and 'std::complex<float>')

     34:      This deficiency means one may need to write cumbersome code while working with the C++ complex classes.

     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.

     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: */

     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: };

     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: }

     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: }

     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: }

     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: }

     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: }

     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: }

     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: }

    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: }

    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: }

    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: }

    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: }

    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: }

    135: #endif