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