1 // boost cast.hpp header file ----------------------------------------------// 2 3 // (C) Copyright Kevlin Henney and Dave Abrahams 1999. 4 // Distributed under the Boost 5 // Software License, Version 1.0. (See accompanying file 6 // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 7 8 // See http://www.boost.org/libs/conversion for Documentation. 9 10 // Revision History 11 // 02 Jun 14 Remove VC6 workarounds. 12 // 16 Jul 11 Bugfixes for VC6. 13 // 23 JUN 05 Code extracted from /boost/cast.hpp into this new header. 14 // Keeps this legacy version of numeric_cast<> for old compilers 15 // wich can't compile the new version in /boost/numeric/conversion/cast.hpp 16 // (Fernando Cacciola) 17 // 02 Apr 01 Removed BOOST_NO_LIMITS workarounds and included 18 // <boost/limits.hpp> instead (the workaround did not 19 // actually compile when BOOST_NO_LIMITS was defined in 20 // any case, so we loose nothing). (John Maddock) 21 // 21 Jan 01 Undid a bug I introduced yesterday. numeric_cast<> never 22 // worked with stock GCC; trying to get it to do that broke 23 // vc-stlport. 24 // 20 Jan 01 Moved BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS to config.hpp. 25 // Removed unused BOOST_EXPLICIT_TARGET macro. Moved 26 // boost::detail::type to boost/type.hpp. Made it compile with 27 // stock gcc again (Dave Abrahams) 28 // 29 Nov 00 Remove nested namespace cast, cleanup spacing before Formal 29 // Review (Beman Dawes) 30 // 19 Oct 00 Fix numeric_cast for floating-point types (Dave Abrahams) 31 // 15 Jul 00 Suppress numeric_cast warnings for GCC, Borland and MSVC 32 // (Dave Abrahams) 33 // 30 Jun 00 More MSVC6 wordarounds. See comments below. (Dave Abrahams) 34 // 28 Jun 00 Removed implicit_cast<>. See comment below. (Beman Dawes) 35 // 27 Jun 00 More MSVC6 workarounds 36 // 15 Jun 00 Add workarounds for MSVC6 37 // 2 Feb 00 Remove bad_numeric_cast ";" syntax error (Doncho Angelov) 38 // 26 Jan 00 Add missing throw() to bad_numeric_cast::what(0 (Adam Levar) 39 // 29 Dec 99 Change using declarations so usages in other namespaces work 40 // correctly (Dave Abrahams) 41 // 23 Sep 99 Change polymorphic_downcast assert to also detect M.I. errors 42 // as suggested Darin Adler and improved by Valentin Bonnard. 43 // 2 Sep 99 Remove controversial asserts, simplify, rename. 44 // 30 Aug 99 Move to cast.hpp, replace value_cast with numeric_cast, 45 // place in nested namespace. 46 // 3 Aug 99 Initial version 47 48 #ifndef BOOST_OLD_NUMERIC_CAST_HPP 49 #define BOOST_OLD_NUMERIC_CAST_HPP 50 51 # include <boost/config.hpp> 52 # include <cassert> 53 # include <typeinfo> 54 # include <boost/type.hpp> 55 # include <boost/limits.hpp> 56 # include <boost/numeric/conversion/converter_policies.hpp> 57 58 namespace boost 59 { 60 using numeric::bad_numeric_cast; 61 62 // LEGACY numeric_cast [only for some old broken compilers] --------------------------------------// 63 64 // Contributed by Kevlin Henney 65 66 // numeric_cast ------------------------------------------------------------// 67 68 #if !defined(BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS) || defined(BOOST_SGI_CPP_LIMITS) 69 70 namespace detail 71 { 72 template <class T> 73 struct signed_numeric_limits : std::numeric_limits<T> 74 { BOOST_PREVENT_MACRO_SUBSTITUTIONboost::detail::signed_numeric_limits75 static inline T min BOOST_PREVENT_MACRO_SUBSTITUTION () 76 { 77 return (std::numeric_limits<T>::min)() >= 0 78 // unary minus causes integral promotion, thus the static_cast<> 79 ? static_cast<T>(-(std::numeric_limits<T>::max)()) 80 : (std::numeric_limits<T>::min)(); 81 }; 82 }; 83 84 // Move to namespace boost in utility.hpp? 85 template <class T, bool specialized> 86 struct fixed_numeric_limits_base 87 : public if_true< std::numeric_limits<T>::is_signed > 88 ::BOOST_NESTED_TEMPLATE then< signed_numeric_limits<T>, 89 std::numeric_limits<T> 90 >::type 91 {}; 92 93 template <class T> 94 struct fixed_numeric_limits 95 : fixed_numeric_limits_base<T,(std::numeric_limits<T>::is_specialized)> 96 {}; 97 98 # ifdef BOOST_HAS_LONG_LONG 99 // cover implementations which supply no specialization for long 100 // long / unsigned long long. Not intended to be full 101 // numeric_limits replacements, but good enough for numeric_cast<> 102 template <> 103 struct fixed_numeric_limits_base< ::boost::long_long_type, false> 104 { 105 BOOST_STATIC_CONSTANT(bool, is_specialized = true); 106 BOOST_STATIC_CONSTANT(bool, is_signed = true); BOOST_PREVENT_MACRO_SUBSTITUTIONboost::detail::fixed_numeric_limits_base107 static ::boost::long_long_type max BOOST_PREVENT_MACRO_SUBSTITUTION () 108 { 109 # ifdef LONGLONG_MAX 110 return LONGLONG_MAX; 111 # else 112 return 9223372036854775807LL; // hope this is portable 113 # endif 114 } 115 BOOST_PREVENT_MACRO_SUBSTITUTIONboost::detail::fixed_numeric_limits_base116 static ::boost::long_long_type min BOOST_PREVENT_MACRO_SUBSTITUTION () 117 { 118 # ifdef LONGLONG_MIN 119 return LONGLONG_MIN; 120 # else 121 return -( 9223372036854775807LL )-1; // hope this is portable 122 # endif 123 } 124 }; 125 126 template <> 127 struct fixed_numeric_limits_base< ::boost::ulong_long_type, false> 128 { 129 BOOST_STATIC_CONSTANT(bool, is_specialized = true); 130 BOOST_STATIC_CONSTANT(bool, is_signed = false); BOOST_PREVENT_MACRO_SUBSTITUTIONboost::detail::fixed_numeric_limits_base131 static ::boost::ulong_long_type max BOOST_PREVENT_MACRO_SUBSTITUTION () 132 { 133 # ifdef ULONGLONG_MAX 134 return ULONGLONG_MAX; 135 # else 136 return 0xffffffffffffffffULL; // hope this is portable 137 # endif 138 } 139 BOOST_PREVENT_MACRO_SUBSTITUTIONboost::detail::fixed_numeric_limits_base140 static ::boost::ulong_long_type min BOOST_PREVENT_MACRO_SUBSTITUTION () { return 0; } 141 }; 142 # endif 143 } // namespace detail 144 145 // less_than_type_min - 146 // x_is_signed should be numeric_limits<X>::is_signed 147 // y_is_signed should be numeric_limits<Y>::is_signed 148 // y_min should be numeric_limits<Y>::min() 149 // 150 // check(x, y_min) returns true iff x < y_min without invoking comparisons 151 // between signed and unsigned values. 152 // 153 // "poor man's partial specialization" is in use here. 154 template <bool x_is_signed, bool y_is_signed> 155 struct less_than_type_min 156 { 157 template <class X, class Y> checkboost::less_than_type_min158 static bool check(X x, Y y_min) 159 { return x < y_min; } 160 }; 161 162 template <> 163 struct less_than_type_min<false, true> 164 { 165 template <class X, class Y> checkboost::less_than_type_min166 static bool check(X, Y) 167 { return false; } 168 }; 169 170 template <> 171 struct less_than_type_min<true, false> 172 { 173 template <class X, class Y> checkboost::less_than_type_min174 static bool check(X x, Y) 175 { return x < 0; } 176 }; 177 178 // greater_than_type_max - 179 // same_sign should be: 180 // numeric_limits<X>::is_signed == numeric_limits<Y>::is_signed 181 // y_max should be numeric_limits<Y>::max() 182 // 183 // check(x, y_max) returns true iff x > y_max without invoking comparisons 184 // between signed and unsigned values. 185 // 186 // "poor man's partial specialization" is in use here. 187 template <bool same_sign, bool x_is_signed> 188 struct greater_than_type_max; 189 190 template<> 191 struct greater_than_type_max<true, true> 192 { 193 template <class X, class Y> checkboost::greater_than_type_max194 static inline bool check(X x, Y y_max) 195 { return x > y_max; } 196 }; 197 198 template <> 199 struct greater_than_type_max<false, true> 200 { 201 // What does the standard say about this? I think it's right, and it 202 // will work with every compiler I know of. 203 template <class X, class Y> checkboost::greater_than_type_max204 static inline bool check(X x, Y) 205 { return x >= 0 && static_cast<X>(static_cast<Y>(x)) != x; } 206 }; 207 208 template<> 209 struct greater_than_type_max<true, false> 210 { 211 template <class X, class Y> checkboost::greater_than_type_max212 static inline bool check(X x, Y y_max) 213 { return x > y_max; } 214 }; 215 216 template <> 217 struct greater_than_type_max<false, false> 218 { 219 // What does the standard say about this? I think it's right, and it 220 // will work with every compiler I know of. 221 template <class X, class Y> checkboost::greater_than_type_max222 static inline bool check(X x, Y) 223 { return static_cast<X>(static_cast<Y>(x)) != x; } 224 }; 225 226 #else // use #pragma hacks if available 227 228 namespace detail 229 { 230 # if BOOST_MSVC 231 # pragma warning(push) 232 # pragma warning(disable : 4018) 233 # pragma warning(disable : 4146) 234 #elif defined(BOOST_BORLANDC) 235 # pragma option push -w-8041 236 # endif 237 238 // Move to namespace boost in utility.hpp? 239 template <class T> 240 struct fixed_numeric_limits : public std::numeric_limits<T> 241 { BOOST_PREVENT_MACRO_SUBSTITUTIONboost::detail::fixed_numeric_limits242 static inline T min BOOST_PREVENT_MACRO_SUBSTITUTION () 243 { 244 return std::numeric_limits<T>::is_signed && (std::numeric_limits<T>::min)() >= 0 245 ? T(-(std::numeric_limits<T>::max)()) : (std::numeric_limits<T>::min)(); 246 } 247 }; 248 249 # if BOOST_MSVC 250 # pragma warning(pop) 251 #elif defined(BOOST_BORLANDC) 252 # pragma option pop 253 # endif 254 } // namespace detail 255 256 #endif 257 258 template<typename Target, typename Source> numeric_cast(Source arg)259 inline Target numeric_cast(Source arg) 260 { 261 // typedefs abbreviating respective trait classes 262 typedef detail::fixed_numeric_limits<Source> arg_traits; 263 typedef detail::fixed_numeric_limits<Target> result_traits; 264 265 #if defined(BOOST_STRICT_CONFIG) \ 266 || (!defined(__HP_aCC) || __HP_aCC > 33900) \ 267 && (!defined(BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS) \ 268 || defined(BOOST_SGI_CPP_LIMITS)) 269 // typedefs that act as compile time assertions 270 // (to be replaced by boost compile time assertions 271 // as and when they become available and are stable) 272 typedef bool argument_must_be_numeric[arg_traits::is_specialized]; 273 typedef bool result_must_be_numeric[result_traits::is_specialized]; 274 275 const bool arg_is_signed = arg_traits::is_signed; 276 const bool result_is_signed = result_traits::is_signed; 277 const bool same_sign = arg_is_signed == result_is_signed; 278 279 if (less_than_type_min<arg_is_signed, result_is_signed>::check(arg, (result_traits::min)()) 280 || greater_than_type_max<same_sign, arg_is_signed>::check(arg, (result_traits::max)()) 281 ) 282 283 #else // We need to use #pragma hacks if available 284 285 # if BOOST_MSVC 286 # pragma warning(push) 287 # pragma warning(disable : 4018) 288 #elif defined(BOOST_BORLANDC) 289 #pragma option push -w-8012 290 # endif 291 if ((arg < 0 && !result_traits::is_signed) // loss of negative range 292 || (arg_traits::is_signed && arg < (result_traits::min)()) // underflow 293 || arg > (result_traits::max)()) // overflow 294 # if BOOST_MSVC 295 # pragma warning(pop) 296 #elif defined(BOOST_BORLANDC) 297 #pragma option pop 298 # endif 299 #endif 300 { 301 throw bad_numeric_cast(); 302 } 303 return static_cast<Target>(arg); 304 } // numeric_cast 305 306 } // namespace boost 307 308 #endif // BOOST_OLD_NUMERIC_CAST_HPP 309