old_numeric_cast.hpp 12 KB

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