numeric_cast_traits_test.cpp 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380
  1. //
  2. //! Copyright (c) 2011
  3. //! Brandon Kohn
  4. //
  5. // Distributed under the Boost Software License, Version 1.0. (See
  6. // accompanying file LICENSE_1_0.txt or copy at
  7. // http://www.boost.org/LICENSE_1_0.txt)
  8. //
  9. #include <boost/operators.hpp>
  10. #include <boost/numeric/conversion/cast.hpp>
  11. #include <boost/mpl/for_each.hpp>
  12. #include <boost/mpl/vector.hpp>
  13. #include <boost/cstdint.hpp>
  14. #include <boost/test/minimal.hpp>
  15. //! Define a simple custom number
  16. struct Double
  17. {
  18. Double()
  19. : v(0)
  20. {}
  21. template <typename T>
  22. explicit Double( T v )
  23. : v(static_cast<double>(v))
  24. {}
  25. template <typename T>
  26. Double& operator= ( T t )
  27. {
  28. v = static_cast<double>(t);
  29. return *this;
  30. }
  31. bool operator < ( const Double& rhs ) const
  32. {
  33. return v < rhs.v;
  34. }
  35. template <typename T>
  36. bool operator < ( T rhs ) const
  37. {
  38. return v < static_cast<double>(rhs);
  39. }
  40. template <typename LHS>
  41. friend bool operator < ( const LHS& lhs, const Double& rhs )
  42. {
  43. return lhs < rhs.v;
  44. }
  45. bool operator > ( const Double& rhs ) const
  46. {
  47. return v > rhs.v;
  48. }
  49. template <typename LHS>
  50. friend bool operator > ( const LHS& lhs, const Double& rhs )
  51. {
  52. return lhs > rhs.v;
  53. }
  54. template <typename T>
  55. bool operator > ( T rhs ) const
  56. {
  57. return v > static_cast<double>(rhs);
  58. }
  59. bool operator == ( const Double& rhs ) const
  60. {
  61. return v == rhs.v;
  62. }
  63. template <typename T>
  64. bool operator == ( T rhs ) const
  65. {
  66. return v == static_cast<double>(rhs);
  67. }
  68. template <typename LHS>
  69. friend bool operator == ( const LHS& lhs, const Double& rhs )
  70. {
  71. return lhs == rhs.v;
  72. }
  73. bool operator !() const
  74. {
  75. return v == 0;
  76. }
  77. Double operator -() const
  78. {
  79. return Double(-v);
  80. }
  81. Double& operator +=( const Double& t )
  82. {
  83. v += t.v;
  84. return *this;
  85. }
  86. template <typename T>
  87. Double& operator +=( T t )
  88. {
  89. v += static_cast<double>(t);
  90. return *this;
  91. }
  92. Double& operator -=( const Double& t )
  93. {
  94. v -= t.v;
  95. return *this;
  96. }
  97. template <typename T>
  98. Double& operator -=( T t )
  99. {
  100. v -= static_cast<double>(t);
  101. return *this;
  102. }
  103. Double& operator *= ( const Double& factor )
  104. {
  105. v *= factor.v;
  106. return *this;
  107. }
  108. template <typename T>
  109. Double& operator *=( T t )
  110. {
  111. v *= static_cast<double>(t);
  112. return *this;
  113. }
  114. Double& operator /= (const Double& divisor)
  115. {
  116. v /= divisor.v;
  117. return *this;
  118. }
  119. template <typename T>
  120. Double& operator /=( T t )
  121. {
  122. v /= static_cast<double>(t);
  123. return (*this);
  124. }
  125. double v;
  126. };
  127. //! Define numeric_limits for the custom type.
  128. namespace std
  129. {
  130. template<>
  131. class numeric_limits< Double > : public numeric_limits<double>
  132. {
  133. public:
  134. //! Limit our Double to a range of +/- 100.0
  135. static Double (min)()
  136. {
  137. return Double(1.e-2);
  138. }
  139. static Double (max)()
  140. {
  141. return Double(1.e2);
  142. }
  143. static Double epsilon()
  144. {
  145. return Double( std::numeric_limits<double>::epsilon() );
  146. }
  147. };
  148. }
  149. //! Define range checking and overflow policies.
  150. namespace custom
  151. {
  152. //! Define a custom range checker
  153. template<typename Traits, typename OverFlowHandler>
  154. struct range_checker
  155. {
  156. typedef typename Traits::argument_type argument_type ;
  157. typedef typename Traits::source_type S;
  158. typedef typename Traits::target_type T;
  159. //! Check range of integral types.
  160. static boost::numeric::range_check_result out_of_range( argument_type s )
  161. {
  162. using namespace boost::numeric;
  163. if( s > bounds<T>::highest() )
  164. return cPosOverflow;
  165. else if( s < bounds<T>::lowest() )
  166. return cNegOverflow;
  167. else
  168. return cInRange;
  169. }
  170. static void validate_range ( argument_type s )
  171. {
  172. BOOST_STATIC_ASSERT( std::numeric_limits<T>::is_bounded );
  173. OverFlowHandler()( out_of_range(s) );
  174. }
  175. };
  176. //! Overflow handler
  177. struct positive_overflow{};
  178. struct negative_overflow{};
  179. struct overflow_handler
  180. {
  181. void operator() ( boost::numeric::range_check_result r )
  182. {
  183. using namespace boost::numeric;
  184. if( r == cNegOverflow )
  185. throw negative_overflow() ;
  186. else if( r == cPosOverflow )
  187. throw positive_overflow() ;
  188. }
  189. };
  190. //! Define a rounding policy and specialize on the custom type.
  191. template<class S>
  192. struct Ceil : boost::numeric::Ceil<S>{};
  193. template<>
  194. struct Ceil<Double>
  195. {
  196. typedef Double source_type;
  197. typedef Double const& argument_type;
  198. static source_type nearbyint ( argument_type s )
  199. {
  200. #if !defined(BOOST_NO_STDC_NAMESPACE)
  201. using std::ceil ;
  202. #endif
  203. return Double( ceil(s.v) );
  204. }
  205. typedef boost::mpl::integral_c< std::float_round_style, std::round_toward_infinity> round_style;
  206. };
  207. //! Define a rounding policy and specialize on the custom type.
  208. template<class S>
  209. struct Trunc: boost::numeric::Trunc<S>{};
  210. template<>
  211. struct Trunc<Double>
  212. {
  213. typedef Double source_type;
  214. typedef Double const& argument_type;
  215. static source_type nearbyint ( argument_type s )
  216. {
  217. #if !defined(BOOST_NO_STDC_NAMESPACE)
  218. using std::floor;
  219. #endif
  220. return Double( floor(s.v) );
  221. }
  222. typedef boost::mpl::integral_c< std::float_round_style, std::round_toward_zero> round_style;
  223. };
  224. }//namespace custom;
  225. namespace boost { namespace numeric {
  226. //! Define the numeric_cast_traits specializations on the custom type.
  227. template <typename S>
  228. struct numeric_cast_traits<Double, S>
  229. {
  230. typedef custom::overflow_handler overflow_policy;
  231. typedef custom::range_checker
  232. <
  233. boost::numeric::conversion_traits<Double, S>
  234. , overflow_policy
  235. > range_checking_policy;
  236. typedef boost::numeric::Trunc<S> rounding_policy;
  237. };
  238. template <typename T>
  239. struct numeric_cast_traits<T, Double>
  240. {
  241. typedef custom::overflow_handler overflow_policy;
  242. typedef custom::range_checker
  243. <
  244. boost::numeric::conversion_traits<T, Double>
  245. , overflow_policy
  246. > range_checking_policy;
  247. typedef custom::Trunc<Double> rounding_policy;
  248. };
  249. //! Define the conversion from the custom type to built-in types and vice-versa.
  250. template<typename T>
  251. struct raw_converter< conversion_traits< T, Double > >
  252. {
  253. static T low_level_convert ( const Double& n )
  254. {
  255. return static_cast<T>( n.v );
  256. }
  257. };
  258. template<typename S>
  259. struct raw_converter< conversion_traits< Double, S > >
  260. {
  261. static Double low_level_convert ( const S& n )
  262. {
  263. return Double(n);
  264. }
  265. };
  266. }}//namespace boost::numeric;
  267. #define BOOST_TEST_CATCH_CUSTOM_POSITIVE_OVERFLOW( CastCode ) \
  268. try { CastCode; BOOST_CHECK( false ); } \
  269. catch( custom::positive_overflow& ){} \
  270. catch(...){ BOOST_CHECK( false ); } \
  271. /***/
  272. #define BOOST_TEST_CATCH_CUSTOM_NEGATIVE_OVERFLOW( CastCode ) \
  273. try { CastCode; BOOST_CHECK( false ); } \
  274. catch( custom::negative_overflow& ){} \
  275. catch(...){ BOOST_CHECK( false ); } \
  276. /***/
  277. struct test_cast_traits
  278. {
  279. template <typename T>
  280. void operator()(T) const
  281. {
  282. Double d = boost::numeric_cast<Double>( static_cast<T>(50) );
  283. BOOST_CHECK( d.v == 50. );
  284. T v = boost::numeric_cast<T>( d );
  285. BOOST_CHECK( v == 50 );
  286. }
  287. };
  288. void test_numeric_cast_traits()
  289. {
  290. typedef boost::mpl::vector
  291. <
  292. boost::int8_t
  293. , boost::uint8_t
  294. , boost::int16_t
  295. , boost::uint16_t
  296. , boost::int32_t
  297. , boost::uint32_t
  298. #if !defined( BOOST_NO_INT64_T )
  299. , boost::int64_t
  300. , boost::uint64_t
  301. #endif
  302. , float
  303. , double
  304. , long double
  305. > types;
  306. boost::mpl::for_each<types>( test_cast_traits() );
  307. //! Check overflow handler.
  308. Double d( 56.0 );
  309. BOOST_TEST_CATCH_CUSTOM_POSITIVE_OVERFLOW( d = boost::numeric_cast<Double>( 101 ) );
  310. BOOST_CHECK( d.v == 56. );
  311. BOOST_TEST_CATCH_CUSTOM_NEGATIVE_OVERFLOW( d = boost::numeric_cast<Double>( -101 ) );
  312. BOOST_CHECK( d.v == 56.);
  313. //! Check custom round policy.
  314. d = 5.9;
  315. int five = boost::numeric_cast<int>( d );
  316. BOOST_CHECK( five == 5 );
  317. }
  318. int test_main( int argc, char * argv[] )
  319. {
  320. test_numeric_cast_traits();
  321. return 0;
  322. }
  323. #undef BOOST_TEST_CATCH_CUSTOM_POSITIVE_OVERFLOW
  324. #undef BOOST_TEST_CATCH_CUSTOM_NEGATIVE_OVERFLOW