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