| [221] | 1 | /*********************************************************************** | 
|---|
|  | 2 | * promote.h   Arithmetic type promotion trait class | 
|---|
|  | 3 | * Author: Todd Veldhuizen         (tveldhui@seurat.uwaterloo.ca) | 
|---|
|  | 4 | * | 
|---|
|  | 5 | * Copyright (C) 1997,1998 Todd Veldhuizen <tveldhui@seurat.uwaterloo.ca> | 
|---|
|  | 6 | * | 
|---|
|  | 7 | * This program is free software; you can redistribute it and/or | 
|---|
|  | 8 | * modify it under the terms of the GNU General Public License | 
|---|
|  | 9 | * as published by the Free Software Foundation; either version 2 | 
|---|
|  | 10 | * of the License, or (at your option) any later version. | 
|---|
|  | 11 | * | 
|---|
|  | 12 | * This program is distributed in the hope that it will be useful, | 
|---|
|  | 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|---|
|  | 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | 
|---|
|  | 15 | * GNU General Public License for more details. | 
|---|
|  | 16 | * | 
|---|
|  | 17 | * Suggestions:          blitz-suggest@cybervision.com | 
|---|
|  | 18 | * Bugs:                 blitz-bugs@cybervision.com | 
|---|
|  | 19 | * | 
|---|
|  | 20 | * For more information, please see the Blitz++ Home Page: | 
|---|
|  | 21 | *    http://seurat.uwaterloo.ca/blitz/ | 
|---|
|  | 22 | * | 
|---|
|  | 23 | *************************************************************************** | 
|---|
|  | 24 | */ | 
|---|
|  | 25 |  | 
|---|
|  | 26 | #ifndef BZ_PROMOTE_H | 
|---|
|  | 27 | #define BZ_PROMOTE_H | 
|---|
|  | 28 |  | 
|---|
|  | 29 | #include <blitz/blitz.h> | 
|---|
|  | 30 |  | 
|---|
|  | 31 | BZ_NAMESPACE(blitz) | 
|---|
|  | 32 |  | 
|---|
|  | 33 | #ifdef BZ_TEMPLATE_QUALIFIED_RETURN_TYPE | 
|---|
|  | 34 | #define BZ_PROMOTE(A,B) _bz_typename promote_trait<A,B>::T_promote | 
|---|
|  | 35 | #else | 
|---|
|  | 36 | #define BZ_PROMOTE(A,B) A | 
|---|
|  | 37 | #endif | 
|---|
|  | 38 |  | 
|---|
|  | 39 | #if defined(BZ_PARTIAL_SPECIALIZATION) && !defined(BZ_DISABLE_NEW_PROMOTE) | 
|---|
|  | 40 |  | 
|---|
|  | 41 | /* | 
|---|
|  | 42 | * This compiler supports partial specialization, so type promotion | 
|---|
|  | 43 | * can be done the elegant way.  This implementation is after ideas | 
|---|
|  | 44 | * by Jean-Louis Leroy. | 
|---|
|  | 45 | */ | 
|---|
|  | 46 |  | 
|---|
|  | 47 | template<class T> | 
|---|
|  | 48 | struct precision_trait { | 
|---|
|  | 49 | enum { precisionRank = 0, | 
|---|
|  | 50 | knowPrecisionRank = 0 }; | 
|---|
|  | 51 | }; | 
|---|
|  | 52 |  | 
|---|
|  | 53 | #define BZ_DECLARE_PRECISION(T,rank)          \ | 
|---|
|  | 54 | template<>                                \ | 
|---|
|  | 55 | struct precision_trait<T> {               \ | 
|---|
|  | 56 | enum { precisionRank = rank,          \ | 
|---|
|  | 57 | knowPrecisionRank = 1 };           \ | 
|---|
|  | 58 | }; | 
|---|
|  | 59 |  | 
|---|
|  | 60 | BZ_DECLARE_PRECISION(int,100) | 
|---|
|  | 61 | BZ_DECLARE_PRECISION(unsigned int,200) | 
|---|
|  | 62 | BZ_DECLARE_PRECISION(long,300) | 
|---|
|  | 63 | BZ_DECLARE_PRECISION(unsigned long,400) | 
|---|
|  | 64 | BZ_DECLARE_PRECISION(float,500) | 
|---|
|  | 65 | BZ_DECLARE_PRECISION(double,600) | 
|---|
|  | 66 | BZ_DECLARE_PRECISION(long double,700) | 
|---|
|  | 67 |  | 
|---|
|  | 68 | #ifdef BZ_HAVE_COMPLEX | 
|---|
|  | 69 | BZ_DECLARE_PRECISION(complex<float>,800) | 
|---|
|  | 70 | BZ_DECLARE_PRECISION(complex<double>,900) | 
|---|
|  | 71 | BZ_DECLARE_PRECISION(complex<long double>,1000) | 
|---|
|  | 72 | #endif | 
|---|
|  | 73 |  | 
|---|
|  | 74 | template<class T> | 
|---|
|  | 75 | struct autopromote_trait { | 
|---|
|  | 76 | typedef T T_numtype; | 
|---|
|  | 77 | }; | 
|---|
|  | 78 |  | 
|---|
|  | 79 | #define BZ_DECLARE_AUTOPROMOTE(T1,T2)     \ | 
|---|
|  | 80 | template<>                            \ | 
|---|
|  | 81 | struct autopromote_trait<T1> {        \ | 
|---|
|  | 82 | typedef T2 T_numtype;               \ | 
|---|
|  | 83 | }; | 
|---|
|  | 84 |  | 
|---|
|  | 85 | // These are the odd cases where small integer types | 
|---|
|  | 86 | // are automatically promoted to int or unsigned int for | 
|---|
|  | 87 | // arithmetic. | 
|---|
|  | 88 | BZ_DECLARE_AUTOPROMOTE(bool, int) | 
|---|
|  | 89 | BZ_DECLARE_AUTOPROMOTE(char, int) | 
|---|
|  | 90 | BZ_DECLARE_AUTOPROMOTE(unsigned char, int) | 
|---|
|  | 91 | BZ_DECLARE_AUTOPROMOTE(short int, int) | 
|---|
|  | 92 | BZ_DECLARE_AUTOPROMOTE(short unsigned int, unsigned int) | 
|---|
|  | 93 |  | 
|---|
|  | 94 | template<class T1, class T2, int promoteToT1> | 
|---|
|  | 95 | struct _bz_promote2 { | 
|---|
|  | 96 | typedef T1 T_promote; | 
|---|
|  | 97 | }; | 
|---|
|  | 98 |  | 
|---|
|  | 99 | template<class T1, class T2> | 
|---|
|  | 100 | struct _bz_promote2<T1,T2,0> { | 
|---|
|  | 101 | typedef T2 T_promote; | 
|---|
|  | 102 | }; | 
|---|
|  | 103 |  | 
|---|
|  | 104 | template<class T1_orig, class T2_orig> | 
|---|
|  | 105 | struct promote_trait { | 
|---|
|  | 106 | // Handle promotion of small integers to int/unsigned int | 
|---|
|  | 107 | typedef _bz_typename autopromote_trait<T1_orig>::T_numtype T1; | 
|---|
|  | 108 | typedef _bz_typename autopromote_trait<T2_orig>::T_numtype T2; | 
|---|
|  | 109 |  | 
|---|
|  | 110 | // True if T1 is higher ranked | 
|---|
|  | 111 | enum { | 
|---|
|  | 112 | T1IsBetter = | 
|---|
|  | 113 | BZ_ENUM_CAST(precision_trait<T1>::precisionRank) > | 
|---|
|  | 114 | BZ_ENUM_CAST(precision_trait<T2>::precisionRank), | 
|---|
|  | 115 |  | 
|---|
|  | 116 | // True if we know ranks for both T1 and T2 | 
|---|
|  | 117 | knowBothRanks = | 
|---|
|  | 118 | BZ_ENUM_CAST(precision_trait<T1>::knowPrecisionRank) | 
|---|
|  | 119 | && BZ_ENUM_CAST(precision_trait<T2>::knowPrecisionRank), | 
|---|
|  | 120 |  | 
|---|
|  | 121 | // True if we know T1 but not T2 | 
|---|
|  | 122 | knowT1butNotT2 =  BZ_ENUM_CAST(precision_trait<T1>::knowPrecisionRank) | 
|---|
|  | 123 | && !(BZ_ENUM_CAST(precision_trait<T2>::knowPrecisionRank)), | 
|---|
|  | 124 |  | 
|---|
|  | 125 | // True if we know T2 but not T1 | 
|---|
|  | 126 | knowT2butNotT1 =  BZ_ENUM_CAST(precision_trait<T2>::knowPrecisionRank) | 
|---|
|  | 127 | && !(BZ_ENUM_CAST(precision_trait<T1>::knowPrecisionRank)), | 
|---|
|  | 128 |  | 
|---|
|  | 129 | // True if T1 is bigger than T2 | 
|---|
|  | 130 | T1IsLarger = sizeof(T1) >= sizeof(T2), | 
|---|
|  | 131 |  | 
|---|
|  | 132 | // We know T1 but not T2: true | 
|---|
|  | 133 | // We know T2 but not T1: false | 
|---|
|  | 134 | // Otherwise, if T1 is bigger than T2: true | 
|---|
|  | 135 | defaultPromotion = knowT1butNotT2 ? _bz_false : | 
|---|
|  | 136 | (knowT2butNotT1 ? _bz_true : T1IsLarger) | 
|---|
|  | 137 | }; | 
|---|
|  | 138 |  | 
|---|
|  | 139 | // If we have both ranks, then use them. | 
|---|
|  | 140 | // If we have only one rank, then use the unknown type. | 
|---|
|  | 141 | // If we have neither rank, then promote to the larger type. | 
|---|
|  | 142 |  | 
|---|
|  | 143 | enum { | 
|---|
|  | 144 | promoteToT1 = (BZ_ENUM_CAST(knowBothRanks) ? BZ_ENUM_CAST(T1IsBetter) | 
|---|
|  | 145 | : BZ_ENUM_CAST(defaultPromotion)) ? 1 : 0 | 
|---|
|  | 146 | }; | 
|---|
|  | 147 |  | 
|---|
|  | 148 | typedef typename _bz_promote2<T1,T2,promoteToT1>::T_promote T_promote; | 
|---|
|  | 149 | }; | 
|---|
|  | 150 |  | 
|---|
|  | 151 | #else  // !BZ_PARTIAL_SPECIALIZATION | 
|---|
|  | 152 |  | 
|---|
|  | 153 | // No partial specialization -- have to do it the ugly way. | 
|---|
|  | 154 | #include <blitz/promote-old.h> | 
|---|
|  | 155 |  | 
|---|
|  | 156 | #endif // !BZ_PARTIAL_SPECIALIZATION | 
|---|
|  | 157 |  | 
|---|
|  | 158 | BZ_NAMESPACE_END | 
|---|
|  | 159 |  | 
|---|
|  | 160 | #endif // BZ_PROMOTE_H | 
|---|