#ifndef ELLINT_TYPING_HH_INCLUDED #define ELLINT_TYPING_HH_INCLUDED /* Type-checking support implemented with templates. */ #include #include #include #include #include "ellint_common.hh" namespace ellint_carlson { namespace typing { /* Constructs for confining template-matching to complex math. */ template struct is_complex : std::false_type {}; template struct is_complex< std::complex > : std::enable_if< std::is_floating_point::value, std::true_type >::type { typedef RT rtype; typedef std::complex ctype; }; template struct is_real_or_complex_fp : std::integral_constant< bool, std::is_floating_point::value || is_complex::value > {}; /* The decplx struct "de-complexifies" a complex type and obtains the * underlying real type, while doing nothing for an already real type. */ template struct decplx { typedef typename std::remove_cv::type type; }; template struct decplx< std::complex > { typedef typename std::remove_cv::type type; }; template using decplx_t = typename decplx::type; template struct pm_impl {}; template struct pm_impl { typedef T type; }; template struct pm_impl< T, std::complex > { typedef std::complex type; }; template struct pm_impl< std::complex, T > { typedef std::complex type; }; /* "Promote" to complex if one and only one of the types is real. */ template using Promote = typename pm_impl::type; /* Buffer holding the correction terms for multiplication. For real * floating-point types, this is just the same type ("just" numeric type). * For complex types, there must be two buffers, each with length 4, for * holding the EFT terms. */ namespace fpbuftypes { /* Real type (also primary template), empty struct except for the * typedef referring to the numeric type. */ template struct corrbuf { typedef RT type; }; /* Complex type, the typedef refers to the corrbuf type itself. * This works because complex is more specialised than real float. */ template struct corrbuf< std::complex > { /* If selected, this "corrbuf" in the typedef necessarily refers to * the correct type, i.e. this struct with two buffer members. */ typedef corrbuf type; RT value_real[NPOLY]; RT value_imag[NPOLY]; }; } /* In the arithmetic functions, "corrbuf" refers to either the bare (and * real) numeric type or the specialised one for complex arithmetic, based * on template matching. This is a convenient type alias referring back to * the (either towards the bare thing or self-referential) type. */ template using corrbuf = typename fpbuftypes::corrbuf::type; /* For use in function return type declaration, optional arguments, * template specialisation, inheritance, etc., where std::enable_if is * appropriate. */ template using real_only = typename std::enable_if::value, ret_t>::type; template using cplx_only = typename std::enable_if::value, ret_t>::type; template using real_or_cplx = typename std::enable_if::value, ret_t>::type; /* Constants for different sizes of floating-point number. The struct * simply retrieves the information from the scope of the specialisation * std::numeric_limit. */ template constexpr real_only nan() { return std::numeric_limits::quiet_NaN(); } template constexpr real_only huge() { return std::numeric_limits::infinity(); } template constexpr real_only half_epsilon() { return std::numeric_limits::epsilon() * (T)0.5; } /* Complexified specialisation, with the complex NaN and infinity as * return values. */ template constexpr cplx_only nan() { typedef decplx_t RT; return T{nan(), nan()}; } template constexpr cplx_only huge() { typedef decplx_t RT; return T{huge(), (RT)0.0}; } }} /* namespace ellint_carlson::typing */ /* Helper macros for use elsewhere in the implementation functions. */ /* For use with iterator expressions. */ #define PIERCE_ITER_REF(ITEXPR) \ typename std::remove_reference::type #define JUST_ELEM(ITEXPR) \ typename std::remove_cv::type #endif /* ELLINT_TYPING_HH_INCLUDED */