//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// /// /// \file /// This file contains the declaration of the mlir::NonFloatComplex type and /// mlir::Complex type alias. The interface is intended to match the /// std::complex type, and the mlir::Complex alias defers to std::complex for /// builtin floating point types. /// //===----------------------------------------------------------------------===// #ifndef MLIR_SUPPORT_COMPLEX_H #define MLIR_SUPPORT_COMPLEX_H #include #include namespace mlir { // The copy constructors should only be implicit iff the underlying constructors // are explicit and the conversion would not narrow. This is the case if the // underlying destination type is copy-list-initializeable from the source type, // so define a helper to determine if that is the case. namespace detail { // NOLINTBEGIN template auto test_copy_list_initializable(int) -> decltype(void(std::declval() = {std::declval()}), std::true_type{}); template auto test_copy_list_initializable(...) -> std::false_type; template struct is_copy_list_initializable : std::bool_constant< decltype(detail::test_copy_list_initializable(0))::value> { }; template constexpr bool is_copy_list_initializable_v = is_copy_list_initializable::value; // NOLINTEND } // namespace detail template class NonFloatComplex { public: using value_type = T; private: T re; T im; public: constexpr NonFloatComplex(const T &re = T{}, const T &im = T{}) : re(re), im(im) {} constexpr NonFloatComplex(const NonFloatComplex &other) = default; template >...> constexpr NonFloatComplex(const NonFloatComplex &other) : re{other.re}, im{other.im} {} template >...> constexpr explicit NonFloatComplex(const NonFloatComplex &other) : re(other.re), im(other.im) {} template >...> constexpr NonFloatComplex(const std::complex &other) : re{other.real()}, im{other.imag()} {} template >...> constexpr explicit NonFloatComplex(const std::complex &other) : re(other.real()), im(other.imag()) {} [[nodiscard]] constexpr T real() const { return re; } constexpr void real(T value) { re = value; } [[nodiscard]] constexpr T imag() const { return im; } constexpr void imag(T value) { im = value; } constexpr NonFloatComplex &operator=(const NonFloatComplex &other) = default; constexpr NonFloatComplex &operator=(const T &real) { re = real; im = T{}; return *this; } constexpr NonFloatComplex &operator+=(const T &real) { re += real; return *this; } constexpr NonFloatComplex &operator-=(const T &real) { re -= real; return *this; } constexpr NonFloatComplex &operator*=(const T &real) { re *= real; im *= real; return *this; } constexpr NonFloatComplex &operator/=(const T &real) { re /= real; im /= real; return *this; } constexpr NonFloatComplex &operator+=(const NonFloatComplex &other) { re += other.re; im += other.im; return *this; } constexpr NonFloatComplex &operator-=(const NonFloatComplex &other) { re -= other.re; im -= other.im; return *this; } constexpr NonFloatComplex &operator*=(const NonFloatComplex &other) { *this = *this * NonFloatComplex{other.re, other.im}; return *this; } constexpr NonFloatComplex &operator/=(const NonFloatComplex &other) { *this = *this / NonFloatComplex{other.re, other.im}; return *this; } template constexpr NonFloatComplex &operator=(const std::complex &other) { re = other.real(); im = other.imag(); return *this; } }; template [[nodiscard]] constexpr NonFloatComplex operator+(const NonFloatComplex &x, const U &y) { NonFloatComplex t{x}; t += y; return t; } template [[nodiscard]] constexpr NonFloatComplex operator-(const NonFloatComplex &x, const U &y) { NonFloatComplex t{x}; t -= y; return t; } template [[nodiscard]] constexpr NonFloatComplex operator*(const NonFloatComplex &x, const NonFloatComplex &y) { T a = x.real(); T b = x.imag(); T c = y.real(); T d = y.imag(); return {(a * c) - (b * d), (a * d) + (b * c)}; } template [[nodiscard]] constexpr NonFloatComplex operator*(const NonFloatComplex &x, const U &y) { NonFloatComplex t{x}; t *= y; return t; } template [[nodiscard]] constexpr NonFloatComplex operator/(const NonFloatComplex &x, const NonFloatComplex &y) { T a = x.real(); T b = x.imag(); T c = y.real(); T d = y.imag(); T denom = c * c + d * d; return {(a * c + b * d) / denom, (b * c - a * d) / denom}; } template [[nodiscard]] constexpr NonFloatComplex operator/(const NonFloatComplex &x, const U &y) { NonFloatComplex t{x}; t /= y; return t; } template [[nodiscard]] constexpr NonFloatComplex operator+(const NonFloatComplex &x) { return x; } template [[nodiscard]] constexpr NonFloatComplex operator-(const NonFloatComplex &x) { return {-x.real(), -x.imag()}; } template [[nodiscard]] constexpr bool operator==(const NonFloatComplex &x, const NonFloatComplex &y) { return x.real() == y.real() && x.imag() == y.imag(); } template [[nodiscard]] constexpr bool operator==(const NonFloatComplex &x, const U &y) { return x == NonFloatComplex{y}; } template [[nodiscard]] constexpr bool operator==(const T &x, const NonFloatComplex &y) { return NonFloatComplex{x} == y; } template [[nodiscard]] constexpr bool operator!=(const NonFloatComplex &x, const NonFloatComplex &y) { return !(x == y); } template [[nodiscard]] constexpr bool operator!=(const NonFloatComplex &x, const U &y) { return !(x == y); } template [[nodiscard]] constexpr bool operator!=(const U &x, const NonFloatComplex &y) { return !(y == x); } template [[nodiscard]] constexpr T real(const NonFloatComplex &x) { return x.real(); } template [[nodiscard]] constexpr T imag(const NonFloatComplex &x) { return x.imag(); } template using Complex = std::conditional_t, std::complex, NonFloatComplex>; } // namespace mlir #endif