X-Git-Url: https://git.dogcows.com/gitweb?p=chaz%2Fyoink;a=blobdiff_plain;f=src%2FMoof%2Fcml%2Fet%2Fscalar_promotions.h;h=5c6a4a1bc60aeeb2a4f6b374506dedc2d0c7a43b;hp=55d033ca5ef52a93053baa679618e5f00f2e8c39;hb=40755d4c6251206c18ce4784967d3a910cee096f;hpb=c2321281bf12a7efaedde930422c7ddbc92080d4 diff --git a/src/Moof/cml/et/scalar_promotions.h b/src/Moof/cml/et/scalar_promotions.h index 55d033c..5c6a4a1 100644 --- a/src/Moof/cml/et/scalar_promotions.h +++ b/src/Moof/cml/et/scalar_promotions.h @@ -13,102 +13,133 @@ Boost Software License, v1.0 (see cml/LICENSE for details). #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 { -/** @class IntPromote - * @brief Helper template to int-promote a type. - */ -template struct IntPromote -{ - /* Signed -> signed int, unsigned -> unsigned int: */ - typedef typename select_switch::result result; +template +struct precision_trait { + enum { precisionRank = 0, + knowPrecisionRank = 0 }; }; -} // namespace detail +#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; +}; -/** @class ScalarPromote - * @brief Template for compile-time type promotion via C promotion rules. - */ -template struct ScalarPromote -{ +#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; +}; - /* Integral-promote the types (if possible). */ - typedef typename detail::IntPromote::result E1; - typedef typename detail::IntPromote::result E2; - - /* If sizeof(long) == sizeof(unsigned int), promote to unsigned long. - * Otherwise, sizeof(long) > sizeof(int), so promote to long. - */ - typedef typename select_if::result uint_promotion; - - /* Do the selection on the promoted types: */ - typedef typename select_switch< - type_pair, - -#if defined(CML_USE_LONG_DOUBLE) - type_pair, long double, - type_pair, long double, - type_pair, long double, -#endif +template +struct promote2 { + typedef T2 T_promote; +}; - type_pair, double, - type_pair, double, - type_pair, double, +template +struct promote_trait { - type_pair, float, - type_pair, float, - type_pair, float, + // Need to remove const-ness: + typedef typename cml::remove_const::type T1_non_const; + typedef typename cml::remove_const::type T2_non_const; - type_pair, void + // Handle promotion of small integers to int/unsigned int + typedef typename autopromote_trait::T_numtype T1; + typedef typename autopromote_trait::T_numtype T2; - >::result float_filter; + // True if T1 is higher ranked + enum { + T1IsBetter = + (int) precision_trait::precisionRank > + (int) precision_trait::precisionRank, - /* The promoted integral types really matter here: */ - typedef typename select_switch< - type_pair, + // True if we know ranks for both T1 and T2 + knowBothRanks = + precision_trait::knowPrecisionRank + && precision_trait::knowPrecisionRank, - type_pair, unsigned long, - type_pair, unsigned long, - type_pair, unsigned long, + // True if we know T1 but not T2 + knowT1butNotT2 = precision_trait::knowPrecisionRank + && !(precision_trait::knowPrecisionRank), - type_pair, long, - type_pair, uint_promotion, - type_pair, uint_promotion, + // True if we know T2 but not T1 + knowT2butNotT1 = precision_trait::knowPrecisionRank + && !(precision_trait::knowPrecisionRank), - type_pair, long, - type_pair, long, + // True if T1 is bigger than T2 + T1IsLarger = sizeof(T1) >= sizeof(T2), - type_pair, unsigned int, - type_pair, unsigned int, - type_pair, unsigned int, + // 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) + }; - type_pair, int, - type_pair, int, - type_pair, int, + // 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. - type_pair, void + enum { + promoteToT1 = (knowBothRanks ? T1IsBetter : defaultPromotion) + ? 1 : 0 + }; - >::result int_filter; + typedef typename promote2::T_promote T_promote; +}; - /* Deduce the final type: */ - typedef typename select_if< - same_type::is_true, - int_filter, float_filter>::result type; +} // namespace detail + +/** Defers to detail::promote_trait<>. */ +template struct ScalarPromote +{ + typedef typename detail::promote_trait::T_promote type; }; } // namespace et