// boost cast.hpp header file ----------------------------------------------// // (C) Copyright Kevlin Henney and Dave Abrahams 1999. // Distributed under the Boost // Software License, Version 1.0. (See accompanying file // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) // See http://www.boost.org/libs/conversion for Documentation. // Revision History // 23 JUN 05 Code extracted from /boost/cast.hpp into this new header. // Keeps this legacy version of numeric_cast<> for old compilers // wich can't compile the new version in /boost/numeric/conversion/cast.hpp // (Fernando Cacciola) // 02 Apr 01 Removed BOOST_NO_LIMITS workarounds and included // instead (the workaround did not // actually compile when BOOST_NO_LIMITS was defined in // any case, so we loose nothing). (John Maddock) // 21 Jan 01 Undid a bug I introduced yesterday. numeric_cast<> never // worked with stock GCC; trying to get it to do that broke // vc-stlport. // 20 Jan 01 Moved BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS to config.hpp. // Removed unused BOOST_EXPLICIT_TARGET macro. Moved // boost::detail::type to boost/type.hpp. Made it compile with // stock gcc again (Dave Abrahams) // 29 Nov 00 Remove nested namespace cast, cleanup spacing before Formal // Review (Beman Dawes) // 19 Oct 00 Fix numeric_cast for floating-point types (Dave Abrahams) // 15 Jul 00 Suppress numeric_cast warnings for GCC, Borland and MSVC // (Dave Abrahams) // 30 Jun 00 More MSVC6 wordarounds. See comments below. (Dave Abrahams) // 28 Jun 00 Removed implicit_cast<>. See comment below. (Beman Dawes) // 27 Jun 00 More MSVC6 workarounds // 15 Jun 00 Add workarounds for MSVC6 // 2 Feb 00 Remove bad_numeric_cast ";" syntax error (Doncho Angelov) // 26 Jan 00 Add missing throw() to bad_numeric_cast::what(0 (Adam Levar) // 29 Dec 99 Change using declarations so usages in other namespaces work // correctly (Dave Abrahams) // 23 Sep 99 Change polymorphic_downcast assert to also detect M.I. errors // as suggested Darin Adler and improved by Valentin Bonnard. // 2 Sep 99 Remove controversial asserts, simplify, rename. // 30 Aug 99 Move to cast.hpp, replace value_cast with numeric_cast, // place in nested namespace. // 3 Aug 99 Initial version #ifndef BOOST_OLD_NUMERIC_CAST_HPP #define BOOST_OLD_NUMERIC_CAST_HPP # include # include # include # include # include # include // It has been demonstrated numerous times that MSVC 6.0 fails silently at link // time if you use a template function which has template parameters that don't // appear in the function's argument list. // // TODO: Add this to config.hpp? // FLC: This macro is repeated in boost/cast.hpp but only locally (is undefined at the bottom) // so is OK to reproduce it here. # if defined(BOOST_MSVC) && BOOST_MSVC < 1300 # define BOOST_EXPLICIT_DEFAULT_TARGET , ::boost::type* = 0 # else # define BOOST_EXPLICIT_DEFAULT_TARGET # endif namespace boost { using numeric::bad_numeric_cast; // LEGACY numeric_cast [only for some old broken compilers] --------------------------------------// // Contributed by Kevlin Henney // numeric_cast ------------------------------------------------------------// #if !defined(BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS) || defined(BOOST_SGI_CPP_LIMITS) namespace detail { template struct signed_numeric_limits : std::numeric_limits { static inline T min BOOST_PREVENT_MACRO_SUBSTITUTION () { return (std::numeric_limits::min)() >= 0 // unary minus causes integral promotion, thus the static_cast<> ? static_cast(-(std::numeric_limits::max)()) : (std::numeric_limits::min)(); }; }; // Move to namespace boost in utility.hpp? template struct fixed_numeric_limits_base : public if_true< std::numeric_limits::is_signed > ::BOOST_NESTED_TEMPLATE then< signed_numeric_limits, std::numeric_limits >::type {}; template struct fixed_numeric_limits : fixed_numeric_limits_base::is_specialized)> {}; # ifdef BOOST_HAS_LONG_LONG // cover implementations which supply no specialization for long // long / unsigned long long. Not intended to be full // numeric_limits replacements, but good enough for numeric_cast<> template <> struct fixed_numeric_limits_base< ::boost::long_long_type, false> { BOOST_STATIC_CONSTANT(bool, is_specialized = true); BOOST_STATIC_CONSTANT(bool, is_signed = true); static ::boost::long_long_type max BOOST_PREVENT_MACRO_SUBSTITUTION () { # ifdef LONGLONG_MAX return LONGLONG_MAX; # else return 9223372036854775807LL; // hope this is portable # endif } static ::boost::long_long_type min BOOST_PREVENT_MACRO_SUBSTITUTION () { # ifdef LONGLONG_MIN return LONGLONG_MIN; # else return -( 9223372036854775807LL )-1; // hope this is portable # endif } }; template <> struct fixed_numeric_limits_base< ::boost::ulong_long_type, false> { BOOST_STATIC_CONSTANT(bool, is_specialized = true); BOOST_STATIC_CONSTANT(bool, is_signed = false); static ::boost::ulong_long_type max BOOST_PREVENT_MACRO_SUBSTITUTION () { # ifdef ULONGLONG_MAX return ULONGLONG_MAX; # else return 0xffffffffffffffffULL; // hope this is portable # endif } static ::boost::ulong_long_type min BOOST_PREVENT_MACRO_SUBSTITUTION () { return 0; } }; # endif } // namespace detail // less_than_type_min - // x_is_signed should be numeric_limits::is_signed // y_is_signed should be numeric_limits::is_signed // y_min should be numeric_limits::min() // // check(x, y_min) returns true iff x < y_min without invoking comparisons // between signed and unsigned values. // // "poor man's partial specialization" is in use here. template struct less_than_type_min { template static bool check(X x, Y y_min) { return x < y_min; } }; template <> struct less_than_type_min { template static bool check(X, Y) { return false; } }; template <> struct less_than_type_min { template static bool check(X x, Y) { return x < 0; } }; // greater_than_type_max - // same_sign should be: // numeric_limits::is_signed == numeric_limits::is_signed // y_max should be numeric_limits::max() // // check(x, y_max) returns true iff x > y_max without invoking comparisons // between signed and unsigned values. // // "poor man's partial specialization" is in use here. template struct greater_than_type_max; template<> struct greater_than_type_max { template static inline bool check(X x, Y y_max) { return x > y_max; } }; template <> struct greater_than_type_max { // What does the standard say about this? I think it's right, and it // will work with every compiler I know of. template static inline bool check(X x, Y) { return x >= 0 && static_cast(static_cast(x)) != x; } # if defined(BOOST_MSVC) && BOOST_MSVC < 1300 // MSVC6 can't static_cast unsigned __int64 -> floating types # define BOOST_UINT64_CAST(src_type) \ static inline bool check(src_type x, unsigned __int64) \ { \ if (x < 0) return false; \ unsigned __int64 y = static_cast(x); \ bool odd = y & 0x1; \ __int64 div2 = static_cast<__int64>(y >> 1); \ return ((static_cast(div2) * 2.0) + odd) != x; \ } BOOST_UINT64_CAST(long double); BOOST_UINT64_CAST(double); BOOST_UINT64_CAST(float); # undef BOOST_UINT64_CAST # endif }; template<> struct greater_than_type_max { template static inline bool check(X x, Y y_max) { return x > y_max; } }; template <> struct greater_than_type_max { // What does the standard say about this? I think it's right, and it // will work with every compiler I know of. template static inline bool check(X x, Y) { return static_cast(static_cast(x)) != x; } }; #else // use #pragma hacks if available namespace detail { # if BOOST_MSVC # pragma warning(push) # pragma warning(disable : 4018) # pragma warning(disable : 4146) #elif defined(__BORLANDC__) # pragma option push -w-8041 # endif // Move to namespace boost in utility.hpp? template struct fixed_numeric_limits : public std::numeric_limits { static inline T min BOOST_PREVENT_MACRO_SUBSTITUTION () { return std::numeric_limits::is_signed && (std::numeric_limits::min)() >= 0 ? T(-(std::numeric_limits::max)()) : (std::numeric_limits::min)(); } }; # if BOOST_MSVC # pragma warning(pop) #elif defined(__BORLANDC__) # pragma option pop # endif } // namespace detail #endif template inline Target numeric_cast(Source arg BOOST_EXPLICIT_DEFAULT_TARGET) { // typedefs abbreviating respective trait classes typedef detail::fixed_numeric_limits arg_traits; typedef detail::fixed_numeric_limits result_traits; #if defined(BOOST_STRICT_CONFIG) \ || (!defined(__HP_aCC) || __HP_aCC > 33900) \ && (!defined(BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS) \ || defined(BOOST_SGI_CPP_LIMITS)) // typedefs that act as compile time assertions // (to be replaced by boost compile time assertions // as and when they become available and are stable) typedef bool argument_must_be_numeric[arg_traits::is_specialized]; typedef bool result_must_be_numeric[result_traits::is_specialized]; const bool arg_is_signed = arg_traits::is_signed; const bool result_is_signed = result_traits::is_signed; const bool same_sign = arg_is_signed == result_is_signed; if (less_than_type_min::check(arg, (result_traits::min)()) || greater_than_type_max::check(arg, (result_traits::max)()) ) #else // We need to use #pragma hacks if available # if BOOST_MSVC # pragma warning(push) # pragma warning(disable : 4018) #elif defined(__BORLANDC__) #pragma option push -w-8012 # endif if ((arg < 0 && !result_traits::is_signed) // loss of negative range || (arg_traits::is_signed && arg < (result_traits::min)()) // underflow || arg > (result_traits::max)()) // overflow # if BOOST_MSVC # pragma warning(pop) #elif defined(__BORLANDC__) #pragma option pop # endif #endif { throw bad_numeric_cast(); } return static_cast(arg); } // numeric_cast # undef BOOST_EXPLICIT_DEFAULT_TARGET } // namespace boost #endif // BOOST_OLD_NUMERIC_CAST_HPP