mirror of
				https://github.com/saitohirga/WSJT-X.git
				synced 2025-10-25 01:50:30 -04:00 
			
		
		
		
	
		
			
				
	
	
		
			310 lines
		
	
	
		
			8.8 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			310 lines
		
	
	
		
			8.8 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| // (C) Copyright 2003, Fernando Luis Cacciola Carballal.
 | |
| //
 | |
| // 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<iostream>
 | |
| #include<iomanip>
 | |
| #include<string>
 | |
| #include<typeinfo>
 | |
| #include<vector>
 | |
| #include<algorithm>
 | |
| 
 | |
| #include "boost/numeric/conversion/converter.hpp"
 | |
| 
 | |
| #ifdef __BORLANDC__
 | |
| #pragma hdrstop
 | |
| #endif
 | |
| 
 | |
| #include "test_helpers.cpp"
 | |
| #include "test_helpers2.cpp"
 | |
| #include "test_helpers3.cpp"
 | |
| 
 | |
| using namespace std ;
 | |
| using namespace boost ;
 | |
| using namespace numeric ;
 | |
| using namespace MyUDT ;
 | |
| 
 | |
| //-------------------------------------------------------------------------
 | |
| // These are the typical steps that are required to install support for
 | |
| // conversions from/to UDT which need special treatment.
 | |
| //-------------------------------------------------------------------------
 | |
| 
 | |
| 
 | |
| 
 | |
| //
 | |
| // (1) Instantiate specific convesions traits.
 | |
| //     This step is only for convenience.
 | |
| //     These traits instances are required in order to define the specializations
 | |
| //     that follow (and which *are required* to make the library work with MyInt and MyFloat)
 | |
| //
 | |
| namespace MyUDT {
 | |
| 
 | |
| typedef conversion_traits<double , MyFloat> MyFloat_to_double_Traits;
 | |
| typedef conversion_traits<int    , MyFloat> MyFloat_to_int_Traits;
 | |
| typedef conversion_traits<MyInt  , MyFloat> MyFloat_to_MyInt_Traits;
 | |
| typedef conversion_traits<int    , MyInt  > MyInt_to_int_Traits;
 | |
| typedef conversion_traits<MyFloat, MyInt  > MyInt_to_MyFloat_Traits;
 | |
| typedef conversion_traits<MyInt  , double > double_to_MyInt_Traits;
 | |
| 
 | |
| } // namespace MyUDT
 | |
| 
 | |
| 
 | |
| //
 | |
| // (2) Define suitable raw converters.
 | |
| //
 | |
| //   Our sample UDTs don't support implicit conversions.
 | |
| //   Therefore, the default raw_converter<> doesn't work,
 | |
| //   and we need to define our own.
 | |
| //
 | |
| //   There are two ways of doing this:
 | |
| //
 | |
| //     (a) One is to simply specialize boost::numeric::raw_converter<> directly.
 | |
| //         This way, the default converter will work out of the box, which means, for instance,
 | |
| //         that numeric_cast<> can be used with these UDTs.
 | |
| //
 | |
| //     (b) Define a user class with the appropriate interface and supply it explicitely
 | |
| //         as a policy to a converter instance.
 | |
| //
 | |
| //   This test uses chice (a).
 | |
| //
 | |
| namespace boost {
 | |
| 
 | |
| namespace numeric {
 | |
| 
 | |
| template<>
 | |
| struct raw_converter<MyUDT::MyFloat_to_double_Traits>
 | |
| {
 | |
|   static double low_level_convert ( MyUDT::MyFloat const&  s )
 | |
|     { return s.to_builtin() ; }
 | |
| } ;
 | |
| 
 | |
| template<>
 | |
| struct raw_converter<MyUDT::MyFloat_to_int_Traits>
 | |
| {
 | |
|   static int low_level_convert ( MyUDT::MyFloat const& s )
 | |
|     { return static_cast<int>( s.to_builtin() ) ; }
 | |
| } ;
 | |
| 
 | |
| template<>
 | |
| struct raw_converter<MyUDT::MyFloat_to_MyInt_Traits>
 | |
| {
 | |
|   static MyUDT::MyInt low_level_convert ( MyUDT::MyFloat const& s )
 | |
|     { return MyUDT::MyInt( static_cast<int>(s.to_builtin()) ) ; }
 | |
| } ;
 | |
| 
 | |
| template<>
 | |
| struct raw_converter<MyUDT::MyInt_to_int_Traits>
 | |
| {
 | |
|   static int low_level_convert ( MyUDT::MyInt const& s ) { return s.to_builtin() ; }
 | |
| } ;
 | |
| 
 | |
| template<>
 | |
| struct raw_converter<MyUDT::MyInt_to_MyFloat_Traits>
 | |
| {
 | |
|   static MyUDT::MyFloat low_level_convert ( MyUDT::MyInt const& s )
 | |
|     {
 | |
|       return MyUDT::MyFloat( static_cast<double>(s.to_builtin()) ) ;
 | |
|     }
 | |
| } ;
 | |
| 
 | |
| template<>
 | |
| struct raw_converter<MyUDT::double_to_MyInt_Traits>
 | |
| {
 | |
|   static MyUDT::MyInt low_level_convert ( double s )
 | |
|     { return MyUDT::MyInt( static_cast<int>(s) ) ; }
 | |
| } ;
 | |
| 
 | |
| } // namespace numeric
 | |
| 
 | |
| } // namespace boost
 | |
| 
 | |
| 
 | |
| 
 | |
| //
 | |
| // (3) Define suitable range checkers
 | |
| //
 | |
| // By default, if a UDT is involved in a conversion, internal range checking is disabled.
 | |
| // This is so because a UDT type can have any sort of range, even unbounded, thus
 | |
| // the library doesn't attempt to automatically figure out the appropriate range checking logic.
 | |
| // (as it does when builtin types are involved)
 | |
| // However, this situation is a bit unsufficient in practice, specially from doing narrowing (subranged)
 | |
| // conversions from UDTs.
 | |
| // The library provides a rudimentary hook to help this out: The user can plug in his own
 | |
| // range checker to the converter instance.
 | |
| //
 | |
| // This test shows how to define and use a custom range checker.
 | |
| //
 | |
| 
 | |
| namespace MyUDT {
 | |
| 
 | |
| //
 | |
| // The following are metaprogramming tools to allow us the implement the
 | |
| // MyCustomRangeChecker generically, for either builtin or UDT types.
 | |
| //
 | |
| 
 | |
| // get_builtin_type<N>::type extracts the built-in type of our UDT's
 | |
| //
 | |
| template<class N> struct get_builtin_type { typedef N type ; } ;
 | |
| template<> struct get_builtin_type<MyInt>   { typedef int type ; } ;
 | |
| template<> struct get_builtin_type<MyFloat> { typedef double type ; } ;
 | |
| 
 | |
| // U extract_builtin ( T s ) returns 's' converted to the corresponding built-in type U.
 | |
| //   
 | |
| template<class N>
 | |
| struct extract_builtin
 | |
| {
 | |
|   static N apply ( N n ) { return n ; }
 | |
| } ;
 | |
| template<>
 | |
| struct extract_builtin<MyInt>
 | |
| {
 | |
|   static int apply ( MyInt const& n ) { return n.to_builtin() ; }
 | |
| } ;
 | |
| template<>
 | |
| struct extract_builtin<MyFloat>
 | |
| {
 | |
|   static double apply ( MyFloat const& n ) { return n.to_builtin() ; }
 | |
| } ;
 | |
| 
 | |
| template<class Traits>
 | |
| struct MyCustomRangeChecker
 | |
| {
 | |
|   typedef typename Traits::argument_type argument_type ;
 | |
| 
 | |
|   // This custom range checker uses the fact that our 'fake' UDT are merely wrappers
 | |
|   // around builtin types; so it just forward the logic to the correspoding range
 | |
|   // checkers for the wrapped builtin types.
 | |
|   //
 | |
|   typedef typename Traits::source_type S ;
 | |
|   typedef typename Traits::target_type T ;
 | |
| 
 | |
|   // NOTE: S and/or T can be either UDT or builtin types.
 | |
| 
 | |
|   typedef typename get_builtin_type<S>::type builtinS ;
 | |
|   typedef typename get_builtin_type<T>::type builtinT ;
 | |
| 
 | |
|   // NOTE: The internal range checker used by default is *built* when you instantiate
 | |
|   // a converter<> with a given Traits according to the properties of the involved types.
 | |
|   // Currently, there is no way to instantiate this range checker as a separate class.
 | |
|   // However, you can see it as part of the interface of the converter
 | |
|   // (since the converter inherits from it)
 | |
|   // Therefore, here we instantiate a converter corresponding to the builtin types to access
 | |
|   // their associated builtin range checker.
 | |
|   //
 | |
|   typedef boost::numeric::converter<builtinT,builtinS> InternalConverter ;
 | |
| 
 | |
|   static range_check_result out_of_range ( argument_type s )
 | |
|     {
 | |
|       return InternalConverter::out_of_range( extract_builtin<S>::apply(s) );
 | |
|     }
 | |
| 
 | |
|   static void validate_range ( argument_type s )
 | |
|     {
 | |
|       return InternalConverter::validate_range( extract_builtin<S>::apply(s) );
 | |
|     }
 | |
| } ;
 | |
| 
 | |
| } // namespace MyUDT
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| //
 | |
| // Test here
 | |
| //
 | |
| 
 | |
| void test_udt_conversions_with_defaults()
 | |
| {
 | |
|   cout << "Testing UDT conversion with default policies\n" ;
 | |
| 
 | |
|   // MyInt <--> int
 | |
| 
 | |
|     int mibv = rand();
 | |
|     MyInt miv(mibv);
 | |
|     TEST_SUCCEEDING_CONVERSION_DEF(MyInt,int,miv,mibv);
 | |
|     TEST_SUCCEEDING_CONVERSION_DEF(int,MyInt,mibv,miv);
 | |
| 
 | |
|   // MyFloat <--> double
 | |
| 
 | |
|     double mfbv = static_cast<double>(rand()) / 3.0 ;
 | |
|     MyFloat mfv (mfbv);
 | |
|     TEST_SUCCEEDING_CONVERSION_DEF(MyFloat,double,mfv,mfbv);
 | |
|     TEST_SUCCEEDING_CONVERSION_DEF(double,MyFloat,mfbv,mfv);
 | |
| 
 | |
|   // MyInt <--> MyFloat
 | |
| 
 | |
|     MyInt   miv2  ( static_cast<int>(mfbv) );
 | |
|     MyFloat miv2F ( static_cast<int>(mfbv) );
 | |
|     MyFloat mfv2  ( static_cast<double>(mibv) );
 | |
|     MyInt   mfv2I ( static_cast<double>(mibv) );
 | |
|     TEST_SUCCEEDING_CONVERSION_DEF(MyFloat,MyInt,miv2F,miv2);
 | |
|     TEST_SUCCEEDING_CONVERSION_DEF(MyInt,MyFloat,mfv2I,mfv2);
 | |
| }
 | |
| 
 | |
| template<class T, class S>
 | |
| struct GenerateCustomConverter
 | |
| {
 | |
|   typedef conversion_traits<T,S> Traits;
 | |
| 
 | |
|   typedef def_overflow_handler         OverflowHandler ;
 | |
|   typedef Trunc<S>                     Float2IntRounder ;
 | |
|   typedef raw_converter<Traits>        RawConverter ;
 | |
|   typedef MyCustomRangeChecker<Traits> RangeChecker ;
 | |
| 
 | |
|   typedef converter<T,S,Traits,OverflowHandler,Float2IntRounder,RawConverter,RangeChecker> type ;
 | |
| } ;
 | |
| 
 | |
| void test_udt_conversions_with_custom_range_checking()
 | |
| {
 | |
|   cout << "Testing UDT conversions with custom range checker\n" ;
 | |
| 
 | |
|   int mibv = rand();
 | |
|   MyFloat mfv ( static_cast<double>(mibv) );
 | |
| 
 | |
|   typedef GenerateCustomConverter<MyFloat,int>::type int_to_MyFloat_Conv ;
 | |
| 
 | |
|   TEST_SUCCEEDING_CONVERSION( int_to_MyFloat_Conv, MyFloat, int, mfv, mibv );
 | |
| 
 | |
|   int mibv2 = rand();
 | |
|   MyInt miv (mibv2);
 | |
|   MyFloat mfv2 ( static_cast<double>(mibv2) );
 | |
| 
 | |
|   typedef GenerateCustomConverter<MyFloat,MyInt>::type MyInt_to_MyFloat_Conv ;
 | |
| 
 | |
|   TEST_SUCCEEDING_CONVERSION( MyInt_to_MyFloat_Conv, MyFloat, MyInt, mfv2, miv );
 | |
| 
 | |
|   double mfbv = bounds<double>::highest();
 | |
|   typedef GenerateCustomConverter<MyInt,double>::type double_to_MyInt_Conv ;
 | |
| 
 | |
|   TEST_POS_OVERFLOW_CONVERSION( double_to_MyInt_Conv, MyInt, double, mfbv );
 | |
| 
 | |
|   MyFloat mfv3 ( bounds<double>::lowest() ) ;
 | |
|   typedef GenerateCustomConverter<int,MyFloat>::type MyFloat_to_int_Conv ;
 | |
| 
 | |
|   TEST_NEG_OVERFLOW_CONVERSION( MyFloat_to_int_Conv, int, MyFloat, mfv3 );
 | |
| }
 | |
| 
 | |
| 
 | |
| int test_main( int, char* [] )
 | |
| {
 | |
|   cout << setprecision( numeric_limits<long double>::digits10 ) ;
 | |
| 
 | |
|   test_udt_conversions_with_defaults();
 | |
|   test_udt_conversions_with_custom_range_checking();
 | |
| 
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 | |
| 
 |