/* -*- C++ -*- ------------------------------------------------------------ Copyright (c) 2007 Jesse Anders and Demian Nave http://cmldev.net/ The Configurable Math Library (CML) is distributed under the terms of the Boost Software License, v1.0 (see cml/LICENSE for details). *-----------------------------------------------------------------------*/ /** @file * @brief */ #ifndef scalar_promotions_h #define scalar_promotions_h #include #include namespace cml { namespace et { /* The type promotion code below is a slightly modified version of: * http://ubiety.uwaterloo.ca/~tveldhui/papers/techniques/techniques01.html */ namespace detail { template struct precision_trait { enum { precisionRank = 0, knowPrecisionRank = 0 }; }; #define DECLARE_PRECISION(T,rank) \ template<> \ struct precision_trait< T > { \ enum { precisionRank = rank, \ knowPrecisionRank = 1 }; \ }; DECLARE_PRECISION(int,100) DECLARE_PRECISION(unsigned int,200) DECLARE_PRECISION(long,300) DECLARE_PRECISION(unsigned long,400) DECLARE_PRECISION(long long,425) DECLARE_PRECISION(unsigned long long,475) DECLARE_PRECISION(float,500) DECLARE_PRECISION(double,600) DECLARE_PRECISION(long double,700) DECLARE_PRECISION(std::complex,800) DECLARE_PRECISION(std::complex,900) DECLARE_PRECISION(std::complex,1000) template struct autopromote_trait { typedef T T_numtype; }; #define DECLARE_AUTOPROMOTE(T1,T2) \ template<> \ struct autopromote_trait { \ typedef T2 T_numtype; \ }; // These are the odd cases where small integer types // are automatically promoted to int or unsigned int for // arithmetic. DECLARE_AUTOPROMOTE(bool, int) DECLARE_AUTOPROMOTE(char, int) DECLARE_AUTOPROMOTE(unsigned char, int) DECLARE_AUTOPROMOTE(short int, int) DECLARE_AUTOPROMOTE(short unsigned int, unsigned int) template struct promote2 { typedef T1 T_promote; }; template struct promote2 { typedef T2 T_promote; }; template struct promote_trait { // Need to remove const-ness: typedef typename cml::remove_const::type T1_non_const; typedef typename cml::remove_const::type T2_non_const; // Handle promotion of small integers to int/unsigned int typedef typename autopromote_trait::T_numtype T1; typedef typename autopromote_trait::T_numtype T2; // True if T1 is higher ranked enum { T1IsBetter = (int) precision_trait::precisionRank > (int) precision_trait::precisionRank, // True if we know ranks for both T1 and T2 knowBothRanks = precision_trait::knowPrecisionRank && precision_trait::knowPrecisionRank, // True if we know T1 but not T2 knowT1butNotT2 = precision_trait::knowPrecisionRank && !(precision_trait::knowPrecisionRank), // True if we know T2 but not T1 knowT2butNotT1 = precision_trait::knowPrecisionRank && !(precision_trait::knowPrecisionRank), // True if T1 is bigger than T2 T1IsLarger = sizeof(T1) >= sizeof(T2), // We know T1 but not T2: true // We know T2 but not T1: false // Otherwise, if T1 is bigger than T2: true defaultPromotion = knowT1butNotT2 ? false : (knowT2butNotT1 ? true : T1IsLarger) }; // If we have both ranks, then use them. // If we have only one rank, then use the unknown type. // If we have neither rank, then promote to the larger type. enum { promoteToT1 = (knowBothRanks ? T1IsBetter : defaultPromotion) ? 1 : 0 }; typedef typename promote2::T_promote T_promote; }; } // namespace detail /** Defers to detail::promote_trait<>. */ template struct ScalarPromote { typedef typename detail::promote_trait::T_promote type; }; } // namespace et } // namespace cml #endif // ------------------------------------------------------------------------- // vim:ft=cpp