mirror of
				https://github.com/saitohirga/WSJT-X.git
				synced 2025-10-31 13:10:19 -04:00 
			
		
		
		
	
		
			
	
	
		
			381 lines
		
	
	
		
			9.2 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
		
		
			
		
	
	
			381 lines
		
	
	
		
			9.2 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
|  | //
 | ||
|  | //! Copyright (c) 2011
 | ||
|  | //! Brandon Kohn
 | ||
|  | //
 | ||
|  | //  Distributed under the Boost Software License, Version 1.0. (See
 | ||
|  | //  accompanying file LICENSE_1_0.txt or copy at
 | ||
|  | //  http://www.boost.org/LICENSE_1_0.txt)
 | ||
|  | //
 | ||
|  | 
 | ||
|  | #include <boost/operators.hpp>
 | ||
|  | #include <boost/numeric/conversion/cast.hpp>
 | ||
|  | #include <boost/mpl/for_each.hpp>
 | ||
|  | #include <boost/mpl/vector.hpp>
 | ||
|  | #include <boost/cstdint.hpp>
 | ||
|  | #include <boost/test/minimal.hpp>
 | ||
|  | 
 | ||
|  | //! Define a simple custom number
 | ||
|  | struct Double | ||
|  | { | ||
|  |     Double() | ||
|  |         : v(0) | ||
|  |     {} | ||
|  | 
 | ||
|  |     template <typename T> | ||
|  |     explicit Double( T v ) | ||
|  |         : v(static_cast<double>(v)) | ||
|  |     {} | ||
|  | 
 | ||
|  |     template <typename T> | ||
|  |     Double& operator= ( T t ) | ||
|  |     { | ||
|  |         v = static_cast<double>(t); | ||
|  |         return *this; | ||
|  |     } | ||
|  | 
 | ||
|  |     bool operator < ( const Double& rhs ) const | ||
|  |     { | ||
|  |         return v < rhs.v; | ||
|  |     } | ||
|  | 
 | ||
|  |     template <typename T> | ||
|  |     bool operator < ( T rhs ) const | ||
|  |     { | ||
|  |         return v < static_cast<double>(rhs); | ||
|  |     } | ||
|  | 
 | ||
|  |     template <typename LHS> | ||
|  |     friend bool operator < ( const LHS& lhs, const Double& rhs ) | ||
|  |     { | ||
|  |         return lhs < rhs.v; | ||
|  |     } | ||
|  | 
 | ||
|  |     bool operator > ( const Double& rhs ) const | ||
|  |     { | ||
|  |         return v > rhs.v; | ||
|  |     } | ||
|  | 
 | ||
|  |     template <typename LHS> | ||
|  |     friend bool operator > ( const LHS& lhs, const Double& rhs ) | ||
|  |     { | ||
|  |         return lhs > rhs.v; | ||
|  |     } | ||
|  |      | ||
|  |     template <typename T> | ||
|  |     bool operator > ( T rhs ) const | ||
|  |     { | ||
|  |         return v > static_cast<double>(rhs); | ||
|  |     } | ||
|  |      | ||
|  |     bool operator == ( const Double& rhs ) const | ||
|  |     { | ||
|  |         return v == rhs.v; | ||
|  |     } | ||
|  |      | ||
|  |     template <typename T> | ||
|  |     bool operator == ( T rhs ) const | ||
|  |     { | ||
|  |         return v == static_cast<double>(rhs); | ||
|  |     } | ||
|  | 
 | ||
|  |     template <typename LHS> | ||
|  |     friend bool operator == ( const LHS& lhs, const Double& rhs ) | ||
|  |     { | ||
|  |         return lhs == rhs.v; | ||
|  |     } | ||
|  |      | ||
|  |     bool operator !() const | ||
|  |     { | ||
|  |         return v == 0;  | ||
|  |     } | ||
|  |      | ||
|  |     Double operator -() const | ||
|  |     { | ||
|  |         return Double(-v); | ||
|  |     } | ||
|  |      | ||
|  |     Double& operator +=( const Double& t ) | ||
|  |     { | ||
|  |         v += t.v; | ||
|  |         return *this; | ||
|  |     } | ||
|  |      | ||
|  |     template <typename T> | ||
|  |     Double& operator +=( T t ) | ||
|  |     { | ||
|  |         v += static_cast<double>(t); | ||
|  |         return *this; | ||
|  |     } | ||
|  |      | ||
|  |     Double& operator -=( const Double& t ) | ||
|  |     { | ||
|  |         v -= t.v; | ||
|  |         return *this; | ||
|  |     } | ||
|  |      | ||
|  |     template <typename T> | ||
|  |     Double& operator -=( T t ) | ||
|  |     { | ||
|  |         v -= static_cast<double>(t); | ||
|  |         return *this; | ||
|  |     } | ||
|  |      | ||
|  |     Double& operator *= ( const Double& factor ) | ||
|  |     { | ||
|  |         v *= factor.v; | ||
|  |         return *this; | ||
|  |     } | ||
|  |      | ||
|  |     template <typename T> | ||
|  |     Double& operator *=( T t ) | ||
|  |     { | ||
|  |         v *= static_cast<double>(t); | ||
|  |         return *this; | ||
|  |     } | ||
|  | 
 | ||
|  |     Double& operator /= (const Double& divisor) | ||
|  |     { | ||
|  |         v /= divisor.v; | ||
|  |         return *this; | ||
|  |     } | ||
|  |      | ||
|  |     template <typename T> | ||
|  |     Double& operator /=( T t ) | ||
|  |     { | ||
|  |          v /= static_cast<double>(t); | ||
|  |         return (*this);        | ||
|  |     } | ||
|  |      | ||
|  |     double v; | ||
|  | }; | ||
|  | 
 | ||
|  | //! Define numeric_limits for the custom type.
 | ||
|  | namespace std | ||
|  | { | ||
|  |     template<> | ||
|  |     class numeric_limits< Double > : public numeric_limits<double> | ||
|  |     { | ||
|  |     public: | ||
|  | 
 | ||
|  |         //! Limit our Double to a range of +/- 100.0
 | ||
|  |         static Double (min)() | ||
|  |         {             | ||
|  |             return Double(1.e-2); | ||
|  |         } | ||
|  | 
 | ||
|  |         static Double (max)() | ||
|  |         { | ||
|  |             return Double(1.e2); | ||
|  |         } | ||
|  | 
 | ||
|  |         static Double epsilon() | ||
|  |         { | ||
|  |             return Double( std::numeric_limits<double>::epsilon() ); | ||
|  |         } | ||
|  |     }; | ||
|  | } | ||
|  | 
 | ||
|  | //! Define range checking and overflow policies.
 | ||
|  | namespace custom | ||
|  | { | ||
|  |     //! Define a custom range checker
 | ||
|  |     template<typename Traits, typename OverFlowHandler> | ||
|  |     struct range_checker | ||
|  |     { | ||
|  |         typedef typename Traits::argument_type argument_type ; | ||
|  |         typedef typename Traits::source_type S; | ||
|  |         typedef typename Traits::target_type T; | ||
|  |          | ||
|  |         //! Check range of integral types.
 | ||
|  |         static boost::numeric::range_check_result out_of_range( argument_type s ) | ||
|  |         { | ||
|  |             using namespace boost::numeric; | ||
|  |             if( s > bounds<T>::highest() ) | ||
|  |                 return cPosOverflow; | ||
|  |             else if( s < bounds<T>::lowest() ) | ||
|  |                 return cNegOverflow; | ||
|  |             else | ||
|  |                 return cInRange; | ||
|  |         } | ||
|  | 
 | ||
|  |         static void validate_range ( argument_type s ) | ||
|  |         { | ||
|  |             BOOST_STATIC_ASSERT( std::numeric_limits<T>::is_bounded ); | ||
|  |             OverFlowHandler()( out_of_range(s) ); | ||
|  |         } | ||
|  |     }; | ||
|  | 
 | ||
|  |     //! Overflow handler
 | ||
|  |     struct positive_overflow{}; | ||
|  |     struct negative_overflow{}; | ||
|  | 
 | ||
|  |     struct overflow_handler | ||
|  |     { | ||
|  |         void operator() ( boost::numeric::range_check_result r ) | ||
|  |         { | ||
|  |             using namespace boost::numeric; | ||
|  |             if( r == cNegOverflow ) | ||
|  |                 throw negative_overflow() ; | ||
|  |             else if( r == cPosOverflow ) | ||
|  |                 throw positive_overflow() ; | ||
|  |         } | ||
|  |     }; | ||
|  | 
 | ||
|  |     //! Define a rounding policy and specialize on the custom type.
 | ||
|  |     template<class S> | ||
|  |     struct Ceil : boost::numeric::Ceil<S>{}; | ||
|  | 
 | ||
|  |     template<> | ||
|  |     struct Ceil<Double> | ||
|  |     { | ||
|  |       typedef Double source_type; | ||
|  | 
 | ||
|  |       typedef Double const& argument_type; | ||
|  | 
 | ||
|  |       static source_type nearbyint ( argument_type s ) | ||
|  |       { | ||
|  | #if !defined(BOOST_NO_STDC_NAMESPACE)
 | ||
|  |           using std::ceil ; | ||
|  | #endif
 | ||
|  |           return Double( ceil(s.v) ); | ||
|  |       } | ||
|  | 
 | ||
|  |       typedef boost::mpl::integral_c< std::float_round_style, std::round_toward_infinity> round_style; | ||
|  |     }; | ||
|  | 
 | ||
|  |     //! Define a rounding policy and specialize on the custom type.
 | ||
|  |     template<class S> | ||
|  |     struct Trunc: boost::numeric::Trunc<S>{}; | ||
|  | 
 | ||
|  |     template<> | ||
|  |     struct Trunc<Double> | ||
|  |     { | ||
|  |       typedef Double source_type; | ||
|  | 
 | ||
|  |       typedef Double const& argument_type; | ||
|  | 
 | ||
|  |       static source_type nearbyint ( argument_type s ) | ||
|  |       { | ||
|  | #if !defined(BOOST_NO_STDC_NAMESPACE)
 | ||
|  |           using std::floor; | ||
|  | #endif
 | ||
|  |           return Double( floor(s.v) ); | ||
|  |       } | ||
|  | 
 | ||
|  |       typedef boost::mpl::integral_c< std::float_round_style, std::round_toward_zero> round_style; | ||
|  |     }; | ||
|  | }//namespace custom;
 | ||
|  | 
 | ||
|  | namespace boost { namespace numeric { | ||
|  | 
 | ||
|  |     //! Define the numeric_cast_traits specializations on the custom type.
 | ||
|  |     template <typename S> | ||
|  |     struct numeric_cast_traits<Double, S> | ||
|  |     { | ||
|  |         typedef custom::overflow_handler                         overflow_policy; | ||
|  |         typedef custom::range_checker | ||
|  |                 < | ||
|  |                     boost::numeric::conversion_traits<Double, S> | ||
|  |                   , overflow_policy | ||
|  |                 >                                                range_checking_policy; | ||
|  |         typedef boost::numeric::Trunc<S>                         rounding_policy; | ||
|  |     }; | ||
|  |      | ||
|  |     template <typename T> | ||
|  |     struct numeric_cast_traits<T, Double> | ||
|  |     { | ||
|  |         typedef custom::overflow_handler                         overflow_policy; | ||
|  |         typedef custom::range_checker | ||
|  |                 < | ||
|  |                     boost::numeric::conversion_traits<T, Double> | ||
|  |                   , overflow_policy | ||
|  |                 >                                                range_checking_policy; | ||
|  |         typedef custom::Trunc<Double>                            rounding_policy; | ||
|  |     }; | ||
|  | 
 | ||
|  |     //! Define the conversion from the custom type to built-in types and vice-versa.
 | ||
|  |     template<typename T> | ||
|  |     struct raw_converter< conversion_traits< T, Double > > | ||
|  |     { | ||
|  |         static T low_level_convert ( const Double& n ) | ||
|  |         { | ||
|  |             return static_cast<T>( n.v );  | ||
|  |         } | ||
|  |     }; | ||
|  | 
 | ||
|  |     template<typename S> | ||
|  |     struct raw_converter< conversion_traits< Double, S > > | ||
|  |     { | ||
|  |         static Double low_level_convert ( const S& n ) | ||
|  |         { | ||
|  |             return Double(n);  | ||
|  |         } | ||
|  |     }; | ||
|  | }}//namespace boost::numeric;
 | ||
|  | 
 | ||
|  | #define BOOST_TEST_CATCH_CUSTOM_POSITIVE_OVERFLOW( CastCode ) \
 | ||
|  |     try { CastCode; BOOST_CHECK( false ); }                   \ | ||
|  |     catch( custom::positive_overflow& ){}                     \ | ||
|  |     catch(...){ BOOST_CHECK( false ); }                       \ | ||
|  | /***/ | ||
|  | 
 | ||
|  | #define BOOST_TEST_CATCH_CUSTOM_NEGATIVE_OVERFLOW( CastCode ) \
 | ||
|  |     try { CastCode; BOOST_CHECK( false ); }                   \ | ||
|  |     catch( custom::negative_overflow& ){}                     \ | ||
|  |     catch(...){ BOOST_CHECK( false ); }                       \ | ||
|  | /***/ | ||
|  | 
 | ||
|  | struct test_cast_traits | ||
|  | { | ||
|  |     template <typename T> | ||
|  |     void operator()(T) const | ||
|  |     { | ||
|  |         Double d = boost::numeric_cast<Double>( static_cast<T>(50) ); | ||
|  |         BOOST_CHECK( d.v == 50. ); | ||
|  |         T v = boost::numeric_cast<T>( d ); | ||
|  |         BOOST_CHECK( v == 50 ); | ||
|  |     } | ||
|  | }; | ||
|  | 
 | ||
|  | void test_numeric_cast_traits() | ||
|  | { | ||
|  |     typedef boost::mpl::vector | ||
|  |         < | ||
|  |             boost::int8_t | ||
|  |           , boost::uint8_t | ||
|  |           , boost::int16_t | ||
|  |           , boost::uint16_t | ||
|  |           , boost::int32_t | ||
|  |           , boost::uint32_t | ||
|  | #if !defined( BOOST_NO_INT64_T )
 | ||
|  |           , boost::int64_t | ||
|  |           , boost::uint64_t | ||
|  | #endif
 | ||
|  |           , float | ||
|  |           , double | ||
|  |           , long double  | ||
|  |         > types; | ||
|  |     boost::mpl::for_each<types>( test_cast_traits() ); | ||
|  |          | ||
|  |     //! Check overflow handler.
 | ||
|  |     Double d( 56.0 ); | ||
|  |     BOOST_TEST_CATCH_CUSTOM_POSITIVE_OVERFLOW( d = boost::numeric_cast<Double>( 101 ) ); | ||
|  |     BOOST_CHECK( d.v == 56. ); | ||
|  |     BOOST_TEST_CATCH_CUSTOM_NEGATIVE_OVERFLOW( d = boost::numeric_cast<Double>( -101 ) ); | ||
|  |     BOOST_CHECK( d.v == 56.); | ||
|  | 
 | ||
|  |     //! Check custom round policy.
 | ||
|  |     d = 5.9; | ||
|  |     int five = boost::numeric_cast<int>( d ); | ||
|  |     BOOST_CHECK( five == 5 ); | ||
|  | } | ||
|  | 
 | ||
|  | int test_main( int argc, char * argv[] ) | ||
|  | { | ||
|  |     test_numeric_cast_traits(); | ||
|  |     return 0; | ||
|  | } | ||
|  | 
 | ||
|  | #undef BOOST_TEST_CATCH_CUSTOM_POSITIVE_OVERFLOW
 | ||
|  | #undef BOOST_TEST_CATCH_CUSTOM_NEGATIVE_OVERFLOW
 |