]>
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 | |
11fdf7f2 TL |
11 | // 02 Jun 14 Remove VC6 workarounds. |
12 | // 16 Jul 11 Bugfixes for VC6. | |
7c673cae FG |
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 | ||
7c673cae FG |
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 | { | |
75 | 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); | |
107 | 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 | ||
116 | 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); | |
131 | 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 | ||
140 | 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> | |
158 | 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> | |
166 | 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> | |
174 | 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> | |
194 | 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> | |
204 | static inline bool check(X x, Y) | |
205 | { return x >= 0 && static_cast<X>(static_cast<Y>(x)) != x; } | |
7c673cae FG |
206 | }; |
207 | ||
208 | template<> | |
209 | struct greater_than_type_max<true, false> | |
210 | { | |
211 | template <class X, class Y> | |
212 | 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> | |
222 | 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(__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 | { | |
242 | 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(__BORLANDC__) | |
252 | # pragma option pop | |
253 | # endif | |
254 | } // namespace detail | |
255 | ||
256 | #endif | |
257 | ||
258 | template<typename Target, typename Source> | |
11fdf7f2 | 259 | inline Target numeric_cast(Source arg) |
7c673cae FG |
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(__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(__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 | ||
7c673cae FG |
306 | } // namespace boost |
307 | ||
308 | #endif // BOOST_OLD_NUMERIC_CAST_HPP |