1 // boost cast.hpp header file ----------------------------------------------//
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)
8 // See http://www.boost.org/libs/conversion for Documentation.
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
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
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
48 #ifndef BOOST_OLD_NUMERIC_CAST_HPP
49 #define BOOST_OLD_NUMERIC_CAST_HPP
51 # include <boost/config.hpp>
54 # include <boost/type.hpp>
55 # include <boost/limits.hpp>
56 # include <boost/numeric/conversion/converter_policies.hpp>
60 using numeric::bad_numeric_cast;
62 // LEGACY numeric_cast [only for some old broken compilers] --------------------------------------//
64 // Contributed by Kevlin Henney
66 // numeric_cast ------------------------------------------------------------//
68 #if !defined(BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS) || defined(BOOST_SGI_CPP_LIMITS)
73 struct signed_numeric_limits : std::numeric_limits<T>
75 static inline T min BOOST_PREVENT_MACRO_SUBSTITUTION ()
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)();
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>
94 struct fixed_numeric_limits
95 : fixed_numeric_limits_base<T,(std::numeric_limits<T>::is_specialized)>
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<>
103 struct fixed_numeric_limits_base< ::boost::long_long_type, false>
105 BOOST_STATIC_CONSTANT(bool, is_specialized = true);
106 BOOST_STATIC_CONSTANT(bool, is_signed = true);
107 static ::boost::long_long_type max BOOST_PREVENT_MACRO_SUBSTITUTION ()
112 return 9223372036854775807LL; // hope this is portable
116 static ::boost::long_long_type min BOOST_PREVENT_MACRO_SUBSTITUTION ()
121 return -( 9223372036854775807LL )-1; // hope this is portable
127 struct fixed_numeric_limits_base< ::boost::ulong_long_type, false>
129 BOOST_STATIC_CONSTANT(bool, is_specialized = true);
130 BOOST_STATIC_CONSTANT(bool, is_signed = false);
131 static ::boost::ulong_long_type max BOOST_PREVENT_MACRO_SUBSTITUTION ()
133 # ifdef ULONGLONG_MAX
134 return ULONGLONG_MAX;
136 return 0xffffffffffffffffULL; // hope this is portable
140 static ::boost::ulong_long_type min BOOST_PREVENT_MACRO_SUBSTITUTION () { return 0; }
143 } // namespace detail
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()
150 // check(x, y_min) returns true iff x < y_min without invoking comparisons
151 // between signed and unsigned values.
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
157 template <class X, class Y>
158 static bool check(X x, Y y_min)
159 { return x < y_min; }
163 struct less_than_type_min<false, true>
165 template <class X, class Y>
166 static bool check(X, Y)
171 struct less_than_type_min<true, false>
173 template <class X, class Y>
174 static bool check(X x, Y)
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()
183 // check(x, y_max) returns true iff x > y_max without invoking comparisons
184 // between signed and unsigned values.
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;
191 struct greater_than_type_max<true, true>
193 template <class X, class Y>
194 static inline bool check(X x, Y y_max)
195 { return x > y_max; }
199 struct greater_than_type_max<false, true>
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>
204 static inline bool check(X x, Y)
205 { return x >= 0 && static_cast<X>(static_cast<Y>(x)) != x; }
209 struct greater_than_type_max<true, false>
211 template <class X, class Y>
212 static inline bool check(X x, Y y_max)
213 { return x > y_max; }
217 struct greater_than_type_max<false, false>
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>
222 static inline bool check(X x, Y)
223 { return static_cast<X>(static_cast<Y>(x)) != x; }
226 #else // use #pragma hacks if available
231 # pragma warning(push)
232 # pragma warning(disable : 4018)
233 # pragma warning(disable : 4146)
234 #elif defined(__BORLANDC__)
235 # pragma option push -w-8041
238 // Move to namespace boost in utility.hpp?
240 struct fixed_numeric_limits : public std::numeric_limits<T>
242 static inline T min BOOST_PREVENT_MACRO_SUBSTITUTION ()
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)();
250 # pragma warning(pop)
251 #elif defined(__BORLANDC__)
254 } // namespace detail
258 template<typename Target, typename Source>
259 inline Target numeric_cast(Source arg)
261 // typedefs abbreviating respective trait classes
262 typedef detail::fixed_numeric_limits<Source> arg_traits;
263 typedef detail::fixed_numeric_limits<Target> result_traits;
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];
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;
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)())
283 #else // We need to use #pragma hacks if available
286 # pragma warning(push)
287 # pragma warning(disable : 4018)
288 #elif defined(__BORLANDC__)
289 #pragma option push -w-8012
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
295 # pragma warning(pop)
296 #elif defined(__BORLANDC__)
301 throw bad_numeric_cast();
303 return static_cast<Target>(arg);
308 #endif // BOOST_OLD_NUMERIC_CAST_HPP