//
// Copyright (C) 2012 Intel Corporation.  All rights reserved.
//
// The information and source code contained herein is the exclusive
// property of Intel Corporation and may not be disclosed, examined
// or reproduced in whole or in part without explicit written authorization
// from the company.
//
// cvs_id[] = "$Id$";
//

//
// complex
//
// Replacement header for C++ standard complex
//
// This replacement is necessary to support scalar complex (gnu complex)
// specialization of several complex operators for some data types,
// in particular float and double
//
// The replacement header will include whatever std. complex is in
// the include search path so it is under the control of the user.
//
//

#ifndef _INC_COMPLEX_
#define _INC_COMPLEX_

// Include system header
#include_next <complex>

#if defined(_WIN32) || defined(_WIN64)
#define _OVERRIDE_COMPLEX_SPECIALIZATION_
#endif // _WIN32 || _WIN64

//
// Complex specialization for float and double
//
#ifndef  _OVERRIDE_COMPLEX_SPECIALIZATION_
#define _USE_COMPLEX_SPECIALIZATION_
#endif //  _OVERRIDE_COMPLEX_SPECIALIZATION_

// Ensure specialization is enabled
#if defined _USE_COMPLEX_SPECIALIZATION_ 
// Ensure that we only specialize known complex system headers
// where complex<float> and complex<double> is implemented based on
// built-in complex data types, e.g. __complex__ float
#if defined _GLIBCXX_COMPLEX
namespace std
{
// Check usage correctness
#if !defined(__INTEL_COMPILER)
# error "This Intel <complex> is for use only with the Intel C++ compilers!"
#endif // __INTEL_COMPILER

// Disable error 308, 373 in order to access the private member of
// complex<float|double>. Considered acceptable as members are used in the
// member specialization as well.
#pragma warning(push) 
#pragma warning(disable:308) 
#pragma warning(disable:373) 
    // Specialized conversion assignment:
    //     complex<double> to complex<float>
    //     complex<float> to complex<double>
    template<>
    inline complex<float>&
        complex<float>::operator=(const complex<double>& __z)
    {
        _M_value = __z._M_value;
        return *this;
    }

    template<>
    inline complex<double>&
        complex<double>::operator=(const complex<float>& __z)
    {
        _M_value = __z._M_value;
        return *this;
    }

    // float:
    // Specialization of complex<float> operation to take advantage of
    // built-in complex types and operations

    template<>
    inline complex<float>&
    complex<float>::operator+=(const complex<float>& __z) {
        _M_value += __z._M_value;
        return *this;
    }

    template<>
    inline complex<float>&
    complex<float>::operator-=(const complex<float>& __z) {
        _M_value -= __z._M_value;
        return *this;
    }

    template<>
    inline complex<float>&
    complex<float>::operator*=(const complex<float>& __z) {
        _M_value *= __z._M_value;
        return *this;
    }

    template<>
    inline complex<float>&
    complex<float>::operator/=(const complex<float>& __z) {
        _M_value /= __z._M_value;
        return *this;
    }

    inline complex<float> operator+(const complex<float>& __x,
                                    const complex<float>& __y) {
        return __x._M_value + __y._M_value;
    }

    inline complex<float> operator-(const complex<float>& __x,
                                    const complex<float>& __y) {
        return __x._M_value - __y._M_value;
    }

    inline complex<float> operator*(const complex<float>& __x,
                                    const complex<float>& __y) {
        return __x._M_value * __y._M_value;
    }

    inline complex<float> operator/(const complex<float>& __x,
                                    const complex<float>& __y) {
        return __x._M_value / __y._M_value;
    }

    inline complex<float> operator-(const complex<float>& __x) {
        return -__x._M_value;
    }
    // template version declared inline _GLIBCXX_CONSTEXPR bool
    // which becomes constexpr for C++11, however the replacement
    // header must support gcc 3.4 to 4.7 (2012)
    inline bool operator==(const complex<float>& __x,
                           const complex<float>& __y) {
        return __x._M_value == __y._M_value;
    }

    inline bool operator!=(const complex<float>& __x,
                           const complex<float>& __y) {
        return __x._M_value != __y._M_value;
    }

    inline complex<float> conj(const complex<float>& __z) {
        return ~__z._M_value;
    }

    // double:
    // Specialization of complex<double> operation to take advantage of
    // built-in complex types and operations

    template<>
    inline complex<double>&
    complex<double>::operator+=(const complex<double>& __z) {
        _M_value += __z._M_value;
        return *this;
    }

    template<>
    inline complex<double>&
    complex<double>::operator-=(const complex<double>& __z) {
        _M_value -= __z._M_value;
        return *this;
    }

    template<>
    inline complex<double>&
    complex<double>::operator*=(const complex<double>& __z) {
        _M_value *= __z._M_value;
        return *this;
    }

    template<>
    inline complex<double>&
    complex<double>::operator/=(const complex<double>& __z) {
        _M_value /= __z._M_value;
        return *this;
    }

    inline complex<double> operator+(const complex<double>& __x,
                                     const complex<double>& __y) {
        return __x._M_value + __y._M_value;
    }

    inline complex<double> operator-(const complex<double>& __x,
                                     const complex<double>& __y) {
        return __x._M_value - __y._M_value;
    }

    inline complex<double> operator*(const complex<double>& __x,
                                     const complex<double>& __y) {
        return __x._M_value * __y._M_value;
    }

    inline complex<double> operator/(const complex<double>& __x,
                                     const complex<double>& __y) {
        return __x._M_value / __y._M_value;
    }

    inline complex<double> operator-(const complex<double>& __x) {
        return -__x._M_value;
    }

    inline bool operator==(const complex<double>& __x,
                           const complex<double>& __y) {
        return __x._M_value == __y._M_value;
    }

    inline bool operator!=(const complex<double>& __x,
                           const complex<double>& __y) {
        return __x._M_value != __y._M_value;
    }

    inline complex<double> conj(const complex<double>& __z) {
        return ~__z._M_value;
    }

#pragma warning(pop) 
} // End namespace std

#endif // _GLIBCXX_COMPLEX
#endif // _USE_COMPLEX_SPECIALIZATION_
#endif // _INC_COMPLEX_

