| 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 | 
|---|