early-access version 3088

This commit is contained in:
pineappleEA
2022-11-05 15:35:56 +01:00
parent 4e4fc25ce3
commit b601909c6d
35519 changed files with 5996896 additions and 860 deletions

View File

@@ -0,0 +1,42 @@
# Boost Numeric Conversion Library test Jamfile
#
# Copyright (C) 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)
#
# import testing ;
project numeric_conversion_unit_tests
:
requirements
<include>.
<toolset>gcc:<cxxflags>"-ftemplate-depth-300 -g0"
<toolset>darwin:<cxxflags>"-ftemplate-depth-300 -g0"
;
test-suite minimal
:
[ run bounds_test.cpp ]
[ run traits_test.cpp : : : <toolset>msvc:<cxxflags>/bigobj ]
[ run converter_test.cpp ]
[ run udt_support_test.cpp ]
[ run numeric_cast_test.cpp ]
[ run udt_example_0.cpp ]
[ run numeric_cast_traits_test.cpp ]
;
test-suite full
:
minimal
[ compile-fail compile_fail/built_in_numeric_cast_traits.cpp ]
;
test-suite extra ;
explicit minimal ;
explicit extra ;
# support the old test target
test-suite numeric/conversion : full ;

View File

@@ -0,0 +1,95 @@
// (c) Copyright Fernando Luis Cacciola Carballal 2000-2004
// Use, modification, and distribution is subject to 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)
// See library home page at http://www.boost.org/libs/numeric/conversion
//
// Contact the author at: fernando_cacciola@hotmail.com
//
#include<typeinfo>
#include<iostream>
#include<iomanip>
#include "boost/numeric/conversion/bounds.hpp"
#ifdef BOOST_BORLANDC
#pragma hdrstop
#endif
#include "test_helpers.cpp"
using namespace std ;
using namespace boost ;
using namespace numeric ;
// Test the fields of boost::numeric::bounds<> against the expected values.
//
template<class T>
void test_bounds( T expected_lowest, T expected_highest, T expected_smallest )
{
T lowest = bounds<T>::lowest () ;
T highest = bounds<T>::highest () ;
T smallest = bounds<T>::smallest() ;
BOOST_TEST_EQ(lowest, expected_lowest);
BOOST_TEST_EQ(highest, expected_highest);
BOOST_TEST_EQ(smallest, expected_smallest);
}
template<class T>
void test_bounds_integer( MATCH_FNTPL_ARG(T) )
{
test_bounds( numeric_limits<T>::min BOOST_PREVENT_MACRO_SUBSTITUTION()
, numeric_limits<T>::max BOOST_PREVENT_MACRO_SUBSTITUTION()
, static_cast<T>(1)
) ;
}
template<class T>
void test_bounds_float( MATCH_FNTPL_ARG(T))
{
test_bounds( -numeric_limits<T>::max BOOST_PREVENT_MACRO_SUBSTITUTION ()
, numeric_limits<T>::max BOOST_PREVENT_MACRO_SUBSTITUTION ()
, numeric_limits<T>::min BOOST_PREVENT_MACRO_SUBSTITUTION ()
) ;
}
void test_bounds_integers()
{
test_bounds_integer( SET_FNTPL_ARG(unsigned char) ) ;
test_bounds_integer( SET_FNTPL_ARG(signed char) ) ;
test_bounds_integer( SET_FNTPL_ARG(char) ) ;
test_bounds_integer( SET_FNTPL_ARG(unsigned short) ) ;
test_bounds_integer( SET_FNTPL_ARG(short) ) ;
test_bounds_integer( SET_FNTPL_ARG(unsigned int) ) ;
test_bounds_integer( SET_FNTPL_ARG(int) ) ;
test_bounds_integer( SET_FNTPL_ARG(unsigned long) ) ;
test_bounds_integer( SET_FNTPL_ARG(long) ) ;
}
void test_bounds_floats()
{
test_bounds_float( SET_FNTPL_ARG(float) );
test_bounds_float( SET_FNTPL_ARG(double) );
test_bounds_float( SET_FNTPL_ARG(long double) );
}
void test_bounds()
{
test_bounds_integers() ;
test_bounds_floats () ;
}
int main( )
{
cout << setprecision( std::numeric_limits<long double>::digits10 ) ;
test_bounds();
return boost::report_errors();
}

View File

@@ -0,0 +1,115 @@
//
//! 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/preprocessor/control/iif.hpp>
#include <boost/preprocessor/comparison/less.hpp>
#include <boost/preprocessor/comparison/not_equal.hpp>
#include <boost/preprocessor/repetition/for.hpp>
#include <boost/preprocessor/tuple/elem.hpp>
#include <boost/preprocessor/seq/elem.hpp>
#include <boost/preprocessor/seq/size.hpp>
//! Generate default traits for the specified source and target.
#define BOOST_NUMERIC_CONVERSION_GENERATE_CAST_TRAITS(r, state) \
template <> \
struct numeric_cast_traits< \
BOOST_PP_SEQ_ELEM( BOOST_PP_TUPLE_ELEM(4,0,state) \
, BOOST_PP_TUPLE_ELEM(4,3,state) ) \
, BOOST_PP_TUPLE_ELEM(4,2,state)> \
{ \
typedef def_overflow_handler overflow_policy; \
typedef UseInternalRangeChecker range_checking_policy; \
typedef Trunc<BOOST_PP_TUPLE_ELEM(4,2,state)> rounding_policy; \
}; \
/***/
#define BOOST_NUMERIC_CONVERSION_TUPLE_SENTINAL(r, state) \
BOOST_PP_LESS \
( \
BOOST_PP_TUPLE_ELEM(4,0,state) \
, BOOST_PP_TUPLE_ELEM(4,1,state) \
) \
/***/
#define BOOST_NUMERIC_CONVERSION_INC_OP(r, state) \
( \
BOOST_PP_INC(BOOST_PP_TUPLE_ELEM(4,0,state)) \
, BOOST_PP_TUPLE_ELEM(4,1,state) \
, BOOST_PP_TUPLE_ELEM(4,2,state) \
, BOOST_PP_TUPLE_ELEM(4,3,state) \
) \
/***/
#define BOOST_NUMERIC_CONVERSION_GENERATE_CAST_TARGET_STEP(r, state) \
BOOST_PP_FOR \
( \
( \
0 \
, BOOST_PP_TUPLE_ELEM(4,1,state) \
, BOOST_PP_SEQ_ELEM(BOOST_PP_TUPLE_ELEM(4,0,state),BOOST_PP_TUPLE_ELEM(4,2,state)) \
, BOOST_PP_TUPLE_ELEM(4,2,state) \
) \
, BOOST_NUMERIC_CONVERSION_TUPLE_SENTINAL \
, BOOST_NUMERIC_CONVERSION_INC_OP \
, BOOST_NUMERIC_CONVERSION_GENERATE_CAST_TRAITS \
) \
/***/
#define BOOST_NUMERIC_CONVERSION_GENERATE_BUILTIN_CAST_TRAITS(types) \
BOOST_PP_FOR \
( \
(0,BOOST_PP_SEQ_SIZE(types),types,_) \
, BOOST_NUMERIC_CONVERSION_TUPLE_SENTINAL \
, BOOST_NUMERIC_CONVERSION_INC_OP \
, BOOST_NUMERIC_CONVERSION_GENERATE_CAST_TARGET_STEP \
) \
/***/
namespace boost { namespace numeric {
#if !defined( BOOST_NO_INT64_T )
//! Generate the specializations for the built-in types.
BOOST_NUMERIC_CONVERSION_GENERATE_BUILTIN_CAST_TRAITS
(
(char)
(boost::int8_t)
(boost::uint8_t)
(boost::int16_t)
(boost::uint16_t)
(boost::int32_t)
(boost::uint32_t)
(boost::int64_t)
(boost::uint64_t)
(float)
(double)
(long double)
)
#else
BOOST_NUMERIC_CONVERSION_GENERATE_BUILTIN_CAST_TRAITS
(
(char)
(boost::int8_t)
(boost::uint8_t)
(boost::int16_t)
(boost::uint16_t)
(boost::int32_t)
(boost::uint32_t)
(float)
(double)
(long double)
)
#endif
}}//namespace boost::numeric;
#undef BOOST_NUMERIC_CONVERSION_GENERATE_BUILTIN_CAST_TRAITS
#undef BOOST_NUMERIC_CONVERSION_GENERATE_CAST_TARGET_STEP
#undef BOOST_NUMERIC_CONVERSION_INC_OP
#undef BOOST_NUMERIC_CONVERSION_TUPLE_SENTINAL
#undef BOOST_NUMERIC_CONVERSION_GENERATE_CAST_TRAITS

View File

@@ -0,0 +1,562 @@
// (c) Copyright Fernando Luis Cacciola Carballal 2000-2004
// Use, modification, and distribution is subject to 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)
// See library home page at http://www.boost.org/libs/numeric/conversion
//
// Contact the author at: fernando_cacciola@hotmail.com
//
#include<cstdlib>
#include<iostream>
#include<iomanip>
#include<string>
#include<typeinfo>
#include<vector>
#include<algorithm>
#include "boost/config.hpp"
#include "boost/cstdint.hpp"
#include "boost/utility.hpp"
//
// Borland 5.5 lacks the following math overloads
//
#if BOOST_WORKAROUND(BOOST_BORLANDC, <= 0x551)
namespace std
{
inline float ceil (float x) { return std::ceil ( static_cast<double>(x)); }
inline float floor (float x) { return std::floor ( static_cast<double>(x)); }
inline long double ceil (long double x) { return std::ceill (x); }
inline long double floor (long double x) { return std::floorl(x); }
} // namespace std
#endif
#include "boost/numeric/conversion/converter.hpp"
#include "boost/numeric/conversion/cast.hpp"
#ifdef BOOST_BORLANDC
#pragma hdrstop
#endif
#include "test_helpers.cpp"
#include "test_helpers2.cpp"
#include "test_helpers3.cpp"
#include "boost/mpl/alias.hpp"
using std::cout ;
// A generic 'abs' function.
template<class N> inline N absG ( N v )
{
return v < static_cast<N>(0) ? static_cast<N>(-v) : v ;
}
template<> inline unsigned char absG<unsigned char> ( unsigned char v ) { return v ; }
template<> inline unsigned short absG<unsigned short> ( unsigned short v ) { return v ; }
template<> inline unsigned int absG<unsigned int> ( unsigned int v ) { return v ; }
template<> inline unsigned long absG<unsigned long> ( unsigned long v ) { return v ; }
template<class T> inline void unused_variable ( T const& ) {}
//
// The following function excersizes specific conversions that cover
// usual and boundary cases for each relevant combination.
//
void test_conversions()
{
using namespace boost ;
using namespace numeric ;
// To help the test found possible bugs a random numbers are used.
#if !defined(BOOST_NO_STDC_NAMESPACE)
using std::rand ;
#endif
boost::int16_t v16 ;
boost::uint16_t uv16 ;
boost::int32_t v32 ;
boost::uint32_t uv32 ;
volatile float fv ; // avoid this to be cached internally in some fpu register
volatile double dv ; // avoid this to be cached internally in some fpu register
//
// sample (representative) conversions:
//
cout << "Testing representative conversions\n";
// integral to integral
// signed to signed
// not subranged
v16 = static_cast<boost::int16_t>(rand());
TEST_SUCCEEDING_CONVERSION_DEF(boost::int32_t,boost::int16_t,v16,v16);
// subranged
v16 = static_cast<boost::int16_t>(rand());
TEST_SUCCEEDING_CONVERSION_DEF(boost::int16_t,boost::int32_t,v16,v16);
TEST_POS_OVERFLOW_CONVERSION_DEF(boost::int16_t,boost::int32_t,bounds<boost::int16_t>::highest() + boost::int32_t(1) ) ;
TEST_NEG_OVERFLOW_CONVERSION_DEF(boost::int16_t,boost::int32_t,bounds<boost::int16_t>::lowest() - boost::int32_t(1) ) ;
// signed to unsigned
// subranged
v32 = absG(static_cast<boost::int32_t>(rand()));
v16 = absG(static_cast<boost::int16_t>(rand()));
TEST_SUCCEEDING_CONVERSION_DEF(boost::uint32_t,boost::int32_t,v32,v32);
TEST_SUCCEEDING_CONVERSION_DEF(boost::uint16_t,boost::int32_t,v16,v16);
TEST_POS_OVERFLOW_CONVERSION_DEF(boost::uint16_t,boost::int32_t,bounds<boost::uint16_t>::highest() + boost::int32_t(1) ) ;
TEST_NEG_OVERFLOW_CONVERSION_DEF(boost::uint32_t,boost::int32_t,boost::int32_t(-1) ) ;
// unsigned to signed
// not subranged
v32 = absG(static_cast<boost::int32_t>(rand()));
TEST_SUCCEEDING_CONVERSION_DEF(boost::int32_t,boost::uint32_t,v32,v32);
// subranged
v16 = absG(static_cast<boost::int16_t>(rand()));
TEST_SUCCEEDING_CONVERSION_DEF(boost::int16_t,boost::uint32_t,v16,v16);
TEST_POS_OVERFLOW_CONVERSION_DEF(boost::int32_t,boost::uint32_t,bounds<boost::uint32_t>::highest() ) ;
TEST_POS_OVERFLOW_CONVERSION_DEF(boost::int16_t,boost::uint32_t,bounds<boost::uint32_t>::highest() ) ;
// unsigned to unsigned
// not subranged
uv16 = static_cast<boost::uint16_t>(rand());
TEST_SUCCEEDING_CONVERSION_DEF(boost::uint32_t,boost::uint16_t,uv16,uv16);
// subranged
uv16 = static_cast<boost::uint16_t>(rand());
TEST_SUCCEEDING_CONVERSION_DEF(boost::uint16_t,boost::uint32_t,uv16,uv16);
TEST_POS_OVERFLOW_CONVERSION_DEF(boost::uint16_t,boost::uint32_t,bounds<boost::uint32_t>::highest() ) ;
// integral to float
// from signed integral
v32 = static_cast<boost::int32_t>(rand());
TEST_SUCCEEDING_CONVERSION_DEF(double,boost::int32_t,v32,v32);
// from uint32_tegral
uv32 = static_cast<boost::uint32_t>(rand());
TEST_SUCCEEDING_CONVERSION_DEF(double,boost::uint32_t,uv32,uv32);
// float to integral
// to signed integral
v32 = static_cast<boost::int32_t>(rand());
TEST_SUCCEEDING_CONVERSION_DEF(boost::int32_t,double,v32,v32);
dv = static_cast<double>(bounds<boost::uint32_t>::highest()) + 1.0 ;
TEST_POS_OVERFLOW_CONVERSION_DEF(boost::int32_t,double,dv) ;
TEST_NEG_OVERFLOW_CONVERSION_DEF(boost::int32_t,double,-dv) ;
// float to float
// not subranged
fv = static_cast<float>(rand()) / static_cast<float>(3) ;
TEST_SUCCEEDING_CONVERSION_DEF(double,float,fv,fv);
// subranged
fv = static_cast<float>(rand()) / static_cast<float>(3) ;
TEST_SUCCEEDING_CONVERSION_DEF(float,double,fv,fv);
TEST_POS_OVERFLOW_CONVERSION_DEF(float,double,bounds<double>::highest()) ;
TEST_NEG_OVERFLOW_CONVERSION_DEF(float,double,bounds<double>::lowest ()) ;
}
// Custom OverflowHandler
struct custom_overflow_handler
{
void operator() ( boost::numeric::range_check_result r )
{
if ( r == boost::numeric::cNegOverflow )
cout << "negative_overflow detected!\n" ;
else if ( r == boost::numeric::cPosOverflow )
cout << "positive_overflow detected!\n" ;
}
} ;
template<class T, class S,class OverflowHandler>
void test_overflow_handler( MATCH_FNTPL_ARG(T), MATCH_FNTPL_ARG(S), MATCH_FNTPL_ARG(OverflowHandler),
PostCondition pos,
PostCondition neg
)
{
typedef boost::numeric::conversion_traits<T,S> traits ;
typedef boost::numeric::converter<T,S,traits,OverflowHandler> converter ;
static const S psrc = boost::numeric::bounds<S>::highest();
static const S nsrc = boost::numeric::bounds<S>::lowest ();
static const T pres = static_cast<T>(psrc);
static const T nres = static_cast<T>(nsrc);
test_conv_base ( ConversionInstance<converter>(pres,psrc,pos) ) ;
test_conv_base ( ConversionInstance<converter>(nres,nsrc,neg) ) ;
}
template<class T, class S>
void test_overflow_handlers( MATCH_FNTPL_ARG(T), MATCH_FNTPL_ARG(S) )
{
cout << "Testing Silent Overflow Handler policy\n";
test_overflow_handler( SET_FNTPL_ARG(T),
SET_FNTPL_ARG(S),
SET_FNTPL_ARG(boost::numeric::silent_overflow_handler),
c_converted,
c_converted
) ;
cout << "Testing Default Overflow Handler policy\n";
test_overflow_handler( SET_FNTPL_ARG(T),
SET_FNTPL_ARG(S),
SET_FNTPL_ARG(boost::numeric::def_overflow_handler),
c_pos_overflow,
c_neg_overflow
) ;
cout << "Testing Custom (User-Defined) Overflow Handler policy\n";
test_overflow_handler( SET_FNTPL_ARG(T),
SET_FNTPL_ARG(S),
SET_FNTPL_ARG(custom_overflow_handler),
c_converted,
c_converted
) ;
}
// For a given float-type number 'n' of integer value (n.0), check the conversions
// within the range [n-1,n+1] taking values at: (n-1,n-0.5,n,n+0.5,n+1).
// For each sampled value there is an expected result and a PostCondition according to the
// specified round_style.
//
template<class T, class S, class Float2IntRounder>
void test_rounding_conversion ( MATCH_FNTPL_ARG(T), MATCH_FNTPL_ARG(Float2IntRounder),
S s,
PostCondition resl1,
PostCondition resl0,
PostCondition res,
PostCondition resr0,
PostCondition resr1
)
{
typedef boost::numeric::conversion_traits<T,S> Traits ;
typedef boost::numeric::converter<T,S, Traits, boost::numeric::def_overflow_handler,Float2IntRounder>
Converter ;
S sl1 = s - static_cast<S>(1);
S sl0 = s - static_cast<S>(0.5);
S sr0 = s + static_cast<S>(0.5);
S sr1 = s + static_cast<S>(1);
T tl1 = static_cast<T>( Converter::nearbyint(sl1) );
T tl0 = static_cast<T>( Converter::nearbyint(sl0) );
T t = static_cast<T>( Converter::nearbyint(s) );
T tr0 = static_cast<T>( Converter::nearbyint(sr0) );
T tr1 = static_cast<T>( Converter::nearbyint(sr1) );
test_conv_base ( ConversionInstance<Converter>(tl1,sl1,resl1) ) ;
test_conv_base ( ConversionInstance<Converter>(tl0,sl0,resl0) ) ;
test_conv_base ( ConversionInstance<Converter>(t,s,res) ) ;
test_conv_base ( ConversionInstance<Converter>(tr0,sr0,resr0) ) ;
test_conv_base ( ConversionInstance<Converter>(tr1,sr1,resr1) ) ;
}
template<class T,class S>
void test_round_style( MATCH_FNTPL_ARG(T), MATCH_FNTPL_ARG(S) )
{
S min = boost::numeric::bounds<T>::lowest();
S max = boost::numeric::bounds<T>::highest();
cout << "Testing 'Trunc' Float2IntRounder policy\n";
test_rounding_conversion(SET_FNTPL_ARG(T),
SET_FNTPL_ARG(boost::numeric::Trunc<S>),
min,
c_neg_overflow,
c_converted,
c_converted,
c_converted,
c_converted
) ;
test_rounding_conversion(SET_FNTPL_ARG(T),
SET_FNTPL_ARG(boost::numeric::Trunc<S>),
max,
c_converted,
c_converted,
c_converted,
c_converted,
c_pos_overflow
) ;
cout << "Testing 'RoundEven' Float2IntRounder policy\n";
test_rounding_conversion(SET_FNTPL_ARG(T),
SET_FNTPL_ARG(boost::numeric::RoundEven<S>),
min,
c_neg_overflow,
c_converted,
c_converted,
c_converted,
c_converted
) ;
test_rounding_conversion(SET_FNTPL_ARG(T),
SET_FNTPL_ARG(boost::numeric::RoundEven<S>),
max,
c_converted,
c_converted,
c_converted,
c_pos_overflow,
c_pos_overflow
) ;
cout << "Testing 'Ceil' Float2IntRounder policy\n";
test_rounding_conversion(SET_FNTPL_ARG(T),
SET_FNTPL_ARG(boost::numeric::Ceil<S>),
min,
c_neg_overflow,
c_converted,
c_converted,
c_converted,
c_converted
) ;
test_rounding_conversion(SET_FNTPL_ARG(T),
SET_FNTPL_ARG(boost::numeric::Ceil<S>),
max,
c_converted,
c_converted,
c_converted,
c_pos_overflow,
c_pos_overflow
) ;
cout << "Testing 'Floor' Float2IntRounder policy\n" ;
test_rounding_conversion(SET_FNTPL_ARG(T),
SET_FNTPL_ARG(boost::numeric::Floor<S>),
min,
c_neg_overflow,
c_neg_overflow,
c_converted,
c_converted,
c_converted
) ;
test_rounding_conversion(SET_FNTPL_ARG(T),
SET_FNTPL_ARG(boost::numeric::Floor<S>),
max,
c_converted,
c_converted,
c_converted,
c_converted,
c_pos_overflow
) ;
}
void test_round_even( double n, double x )
{
double r = boost::numeric::RoundEven<double>::nearbyint(n);
BOOST_TEST( r == x ) ;
}
void test_round_even()
{
cout << "Testing 'RoundEven' tie-breaking\n";
double min = boost::numeric::bounds<double>::lowest();
double max = boost::numeric::bounds<double>::highest();
#if !defined(BOOST_NO_STDC_NAMESPACE)
using std::floor ;
using std::ceil ;
#endif
test_round_even(min, floor(min));
test_round_even(max, ceil (max));
test_round_even(2.0, 2.0);
test_round_even(2.3, 2.0);
test_round_even(2.5, 2.0);
test_round_even(2.7, 3.0);
test_round_even(3.0, 3.0);
test_round_even(3.3, 3.0);
test_round_even(3.5, 4.0);
test_round_even(3.7, 4.0);
}
int double_to_int ( double n ) { return static_cast<int>(n) ; }
void test_converter_as_function_object()
{
cout << "Testing converter as function object.\n";
// Create a sample sequence of double values.
std::vector<double> S ;
for ( int i = 0 ; i < 10 ; ++ i )
S.push_back( i * ( 18.0 / 19.0 ) );
// Create a sequence of int values from 's' using the standard conversion.
std::vector<int> W ;
std::transform(S.begin(),S.end(),std::back_inserter(W),double_to_int);
// Create a sequence of int values from s using a default numeric::converter
std::vector<int> I ;
std::transform(S.begin(),
S.end(),
std::back_inserter(I),
boost::numeric::converter<int,double>()
) ;
// Match 'w' and 'i' which should be equal.
bool double_to_int_OK = std::equal(W.begin(),W.end(),I.begin()) ;
BOOST_TEST(double_to_int_OK);
// Create a sequence of double values from s using a default numeric::converter (which should be the trivial conv).
std::vector<double> D ;
std::transform(S.begin(),
S.end(),
std::back_inserter(D),
boost::numeric::converter<double,double>()
) ;
// Match 's' and 'd' which should be equal.
bool double_to_double_OK = std::equal(S.begin(),S.end(),D.begin()) ;
BOOST_TEST(double_to_double_OK);
}
#if BOOST_WORKAROUND(__IBMCPP__, <= 600 ) // VCAPP6
# define UNOPTIMIZED
#else
# define UNOPTIMIZED volatile
#endif
void test_optimizations()
{
using namespace boost;
using namespace numeric;
float fv0 = 18.0f / 19.0f ;
// This code deosn't produce any output.
// It is intended to show the optimization of numeric::converter<> by manual inspection
// of the generated code.
// Each test shows first the equivalent hand-coded version.
// The numeric_cast<> code should be the same if full compiler optimization/inlining is used.
//---------------------------------
// trivial conversion.
//
// equivalent code:
UNOPTIMIZED float fv1a = fv0 ;
float fv1b = numeric_cast<float>(fv0);
unused_variable(fv1a);
unused_variable(fv1b);
//
//---------------------------------
//---------------------------------
// nonsubranged conversion.
//
// equivalent code:
UNOPTIMIZED double dv1a = static_cast<double>(fv0);
double dv1b = numeric_cast<double>(fv0);
unused_variable(dv1a);
unused_variable(dv1b);
//
//---------------------------------
//------------------------------------------------------
// subranged conversion with both-sided range checking.
//
// equivalent code:
{
double const& s = dv1b ;
// range checking
range_check_result r = s < static_cast<double>(bounds<float>::lowest())
? cNegOverflow : cInRange ;
if ( r == cInRange )
{
r = s > static_cast<double>(bounds<float>::highest()) ? cPosOverflow : cInRange ;
}
if ( r == cNegOverflow )
throw negative_overflow() ;
else if ( r == cPosOverflow )
throw positive_overflow() ;
// conversion
UNOPTIMIZED float fv2a = static_cast<float>(s);
unused_variable(fv2a);
}
float fv2b = numeric_cast<float>(dv1b);
unused_variable(fv2b);
//
//---------------------------------
//---------------------------------
// subranged rounding conversion
//
// equivalent code:
{
double const& s = dv1b ;
// range checking
range_check_result r = s <= static_cast<double>(bounds<int>::lowest()) - static_cast<double>(1.0)
? cNegOverflow : cInRange ;
if ( r == cInRange )
{
r = s >= static_cast<double>(bounds<int>::highest()) + static_cast<double>(1.0)
? cPosOverflow : cInRange ;
}
if ( r == cNegOverflow )
throw negative_overflow() ;
else if ( r == cPosOverflow )
throw positive_overflow() ;
// rounding
#if !defined(BOOST_NO_STDC_NAMESPACE)
using std::floor ;
#endif
double s1 = floor(dv1b + 0.5);
// conversion
UNOPTIMIZED int iv1a = static_cast<int>(s1);
unused_variable(iv1a);
}
int iv1b = numeric_cast<int>(dv1b);
unused_variable(iv1b);
//
//---------------------------------
}
int main()
{
std::cout << std::setprecision( std::numeric_limits<long double>::digits10 ) ;
test_conversions();
test_overflow_handlers( SET_FNTPL_ARG(boost::int16_t), SET_FNTPL_ARG(boost::int32_t));
test_round_style(SET_FNTPL_ARG(boost::int32_t), SET_FNTPL_ARG(double) ) ;
test_round_even() ;
test_converter_as_function_object();
test_optimizations() ;
return boost::report_errors();
}
//---------------------------------------------------------------------------

View File

@@ -0,0 +1,80 @@
// boost utility cast test program -----------------------------------------//
// (C) Copyright Beman Dawes, Dave Abrahams 1999. 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)
// See http://www.boost.org for most recent version including documentation.
// Revision History
// 28 Set 04 taken from the old cast library (Fernando Cacciola)
#include <iostream>
#include <climits>
#include <cfloat> // for DBL_MAX (Peter Schmid)
#include <boost/numeric/conversion/cast.hpp>
#include <boost/core/lightweight_test.hpp>
# if SCHAR_MAX == LONG_MAX
# error "This test program doesn't work if SCHAR_MAX == LONG_MAX"
# endif
using namespace boost;
using std::cout;
int main()
{
# ifdef NDEBUG
cout << "NDEBUG is defined\n";
# else
cout << "NDEBUG is not defined\n";
# endif
cout << "\nBeginning tests...\n";
// test implicit_cast and numeric_cast -------------------------------------//
// tests which should succeed
long small_value = 1;
long small_negative_value = -1;
long large_value = LONG_MAX;
long large_negative_value = LONG_MIN;
signed char c = 0;
c = large_value; // see if compiler generates warning
c = numeric_cast<signed char>( small_value );
BOOST_TEST( c == 1 );
c = 0;
c = numeric_cast<signed char>( small_value );
BOOST_TEST( c == 1 );
c = 0;
c = numeric_cast<signed char>( small_negative_value );
BOOST_TEST( c == -1 );
// These tests courtesy of Joe R NWP Swatosh<joe.r.swatosh@usace.army.mil>
BOOST_TEST( 0.0f == numeric_cast<float>( 0.0 ) );
BOOST_TEST( 0.0 == numeric_cast<double>( 0.0 ) );
// tests which should result in errors being detected
BOOST_TEST_THROWS( numeric_cast<signed char>(large_value),
numeric::bad_numeric_cast );
BOOST_TEST_THROWS( numeric_cast<signed char>(large_negative_value),
numeric::bad_numeric_cast );
BOOST_TEST_THROWS( numeric_cast<signed char>(large_negative_value),
numeric::bad_numeric_cast );
BOOST_TEST_THROWS( numeric_cast<unsigned long>(small_negative_value),
numeric::bad_numeric_cast );
BOOST_TEST_THROWS( numeric_cast<int>(DBL_MAX), numeric::bad_numeric_cast );
return boost::report_errors() ;
} // main

View File

@@ -0,0 +1,377 @@
//
//! 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/core/lightweight_test.hpp>
#include <boost/static_assert.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 ) \
BOOST_TEST_THROWS( CastCode, custom::positive_overflow )
/***/
#define BOOST_TEST_CATCH_CUSTOM_NEGATIVE_OVERFLOW( CastCode ) \
BOOST_TEST_THROWS( CastCode, custom::negative_overflow )
/***/
struct test_cast_traits
{
template <typename T>
void operator()(T) const
{
Double d = boost::numeric_cast<Double>( static_cast<T>(50) );
BOOST_TEST( d.v == 50. );
T v = boost::numeric_cast<T>( d );
BOOST_TEST( 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_TEST( d.v == 56. );
BOOST_TEST_CATCH_CUSTOM_NEGATIVE_OVERFLOW( d = boost::numeric_cast<Double>( -101 ) );
BOOST_TEST( d.v == 56.);
//! Check custom round policy.
d = 5.9;
int five = boost::numeric_cast<int>( d );
BOOST_TEST( five == 5 );
}
int main()
{
test_numeric_cast_traits();
return boost::report_errors();
}
#undef BOOST_TEST_CATCH_CUSTOM_POSITIVE_OVERFLOW
#undef BOOST_TEST_CATCH_CUSTOM_NEGATIVE_OVERFLOW

View File

@@ -0,0 +1,152 @@
// Copyright (C) 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)
//
//
// NOTE: This file is intended to be used ONLY by the test files
// from the Numeric Conversions Library
//
//
#include <cmath>
#include "boost/limits.hpp"
#include "boost/utility.hpp"
#include <boost/core/lightweight_test.hpp>
// Convenience macros to help with compilers which don't parse
// explicit template function instantiations (MSVC6)
#define MATCH_FNTPL_ARG(t) t const*
#define SET_FNTPL_ARG(t) (static_cast< t const* >(0))
//
// *Minimal* example of a User Defined Numeric Type
//
//
namespace MyUDT
{
template<class T>
struct UDT
{
typedef T builtin_type ;
UDT ( T v_ ) : v (v_) {}
T to_builtin() const { return v ; }
friend bool operator == ( UDT const& lhs, UDT const& rhs )
{ return lhs.to_builtin() == rhs.to_builtin() ; }
// NOTE: This operator is *required* by the Numeric Conversion Library
// if Turnc<> is used as the Float2IntRounder policy.
friend bool operator < ( UDT const& lhs, UDT const& rhs )
{ return lhs.to_builtin() < rhs.to_builtin() ; }
friend std::ostream& operator << ( std::ostream& os, UDT const& n )
{ return os << n.to_builtin() ; }
T v ;
} ;
typedef UDT<int> MyInt ;
typedef UDT<double> MyFloat ;
//
// The Float2IntRounder policies *require* a visible 'ceil' or 'floor' math function
// with standard semantics.
// In a conformant compiler, ADL can pick these functions even if they are defined
// within a user namespace, as below.
//
inline MyInt ceil ( MyInt const& x ) { return x ; }
inline MyInt floor ( MyInt const& x ) { return x ; }
inline MyFloat floor ( MyFloat const& x )
{
#if !defined(BOOST_NO_STDC_NAMESPACE)
return MyFloat ( std::floor(x.to_builtin()) ) ;
#else
return MyFloat ( ::floor(x.to_builtin()) ) ;
#endif
}
inline MyFloat ceil ( MyFloat const& x )
{
#if !defined(BOOST_NO_STDC_NAMESPACE)
return MyFloat ( std::ceil(x.to_builtin()) ) ;
#else
return MyFloat ( ::ceil(x.to_builtin()) ) ;
#endif
}
} // namespace MyUDT
//
// The Numeric Conversion Library *requires* User Defined Numeric Types
// to properly specialize std::numeric_limits<>
//
namespace std
{
template<>
class numeric_limits<MyUDT::MyInt> : public numeric_limits<int>
{
public :
BOOST_STATIC_CONSTANT(bool, is_specialized = false);
} ;
template<>
class numeric_limits<MyUDT::MyFloat> : public numeric_limits<double>
{
public :
BOOST_STATIC_CONSTANT(bool, is_specialized = false);
} ;
} // namespace std
//
// The functions floor and ceil defined within namespace MyUDT
// should be found by koenig loopkup, but some compilers don't do it right
// so we inyect them into namespace std so ordinary overload resolution
// can found them.
#if defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP) || defined(BOOST_BORLANDC) || defined(__GNUC__)
namespace std {
using MyUDT::floor ;
using MyUDT::ceil ;
} // namespace std
#endif
std::string to_string( bool arg )
{
return arg ? "true" : "false" ;
}
std::string to_string( ... ) { throw std::runtime_error("to_string() called with wrong type!") ; }
//
// This is used to print 'char' values as numbers instead of characters.
//
template<class T> struct printable_number_type { typedef T type ; } ;
template<> struct printable_number_type<signed char> { typedef int type ; } ;
template<> struct printable_number_type<unsigned char> { typedef unsigned type ; } ;
template<> struct printable_number_type<char> { typedef int type ; } ;
template<class T>
inline
typename printable_number_type<T>::type
printable( T n ) { return n ; }
//
///////////////////////////////////////////////////////////////////////////////////////////////

View File

@@ -0,0 +1,60 @@
// Copyright (C) 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)
//
//
// NOTE: This file is intended to be used ONLY by the test files
// from the Numeric Conversions Library
//
//
// The following 'to_string' helpers are provided to give readable names
// to the various enums used by the library.
// NOTE: specializations of boost::lexical_cast<> were not used since some compilers had
// trouble dealing with such specializations for different enumerations.
//
std::string to_string ( boost::numeric::int_float_mixture_enum arg )
{
switch ( arg )
{
case boost::numeric::integral_to_integral : return "integral_to_integral" ;
case boost::numeric::integral_to_float : return "integral_to_float" ;
case boost::numeric::float_to_integral : return "float_to_integral" ;
case boost::numeric::float_to_float : return "float_to_float" ;
}
return "(Unknown result!)" ;
}
std::string to_string ( boost::numeric::sign_mixture_enum arg )
{
switch ( arg )
{
case boost::numeric::unsigned_to_unsigned : return "unsigned_to_unsigned" ;
case boost::numeric::signed_to_signed : return "signed_to_signed" ;
case boost::numeric::signed_to_unsigned : return "signed_to_unsigned" ;
case boost::numeric::unsigned_to_signed : return "unsigned_to_signed" ;
}
return "(Unknown result!)" ;
}
std::string to_string ( boost::numeric::udt_builtin_mixture_enum arg )
{
switch ( arg )
{
case boost::numeric::builtin_to_builtin : return "builtin_to_builtin" ;
case boost::numeric::builtin_to_udt : return "builtin_to_udt" ;
case boost::numeric::udt_to_builtin : return "udt_to_builtin" ;
case boost::numeric::udt_to_udt : return "udt_to_udt" ;
}
return "(Unknown result!)" ;
}
//
///////////////////////////////////////////////////////////////////////////////////////////////

View File

@@ -0,0 +1,115 @@
// Copyright (C) 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)
//
//
// NOTE: This file is intended to be used ONLY by the test files
// from the Numeric Conversions Library
//
// The conversion test is performed using a class whose instances encapsulate
// a particular specific conversion defnied explicitely.
// A ConversionInstance object includes the source type, the target type,
// the source value and the expected result, including possible exceptions.
//
enum PostCondition { c_converted, c_overflow, c_neg_overflow, c_pos_overflow } ;
template<class Converter>
struct ConversionInstance
{
typedef Converter converter ;
typedef typename Converter::argument_type argument_type ;
typedef typename Converter::result_type result_type ;
typedef typename Converter::traits traits ;
typedef typename traits::target_type target_type ;
typedef typename traits::source_type source_type ;
ConversionInstance ( result_type a_result, argument_type a_source, PostCondition a_post)
:
source(a_source),
result(a_result),
post(a_post)
{}
std::string to_string() const
{
return std::string("converter<")
+ typeid(target_type).name()
+ std::string(",")
+ typeid(source_type).name()
+ std::string(">::convert(") ;
}
argument_type source ;
result_type result ;
PostCondition post ;
} ;
//
// Main conversion test point.
// Exercises a specific conversion described by 'conv'.
//
template<class Instance>
void test_conv_base( Instance const& conv )
{
typedef typename Instance::argument_type argument_type ;
typedef typename Instance::result_type result_type ;
typedef typename Instance::converter converter ;
argument_type source = conv.source ;
try
{
result_type result = converter::convert(source);
if (BOOST_TEST_EQ(conv.post, c_converted))
{
BOOST_TEST_EQ(result, conv.result);
}
}
catch ( boost::numeric::negative_overflow const& )
{
BOOST_TEST_EQ(conv.post, c_neg_overflow);
}
catch ( boost::numeric::positive_overflow const& )
{
BOOST_TEST_EQ(conv.post, c_pos_overflow);
}
catch ( boost::numeric::bad_numeric_cast const& )
{
BOOST_TEST_EQ(conv.post, c_overflow);
}
}
#define TEST_SUCCEEDING_CONVERSION(Conv,typeT,typeS,valueT,valueS) \
test_conv_base( ConversionInstance< Conv >(valueT, valueS, c_converted ) )
#define TEST_POS_OVERFLOW_CONVERSION(Conv,typeT,typeS,valueS) \
test_conv_base( ConversionInstance< Conv >( static_cast< typeT >(0), valueS, c_pos_overflow ) )
#define TEST_NEG_OVERFLOW_CONVERSION(Conv,typeT,typeS,valueS) \
test_conv_base( ConversionInstance< Conv >( static_cast< typeT >(0), valueS, c_neg_overflow ) )
#define DEF_CONVERTER(T,S) boost::numeric::converter< T , S >
#define TEST_SUCCEEDING_CONVERSION_DEF(typeT,typeS,valueT,valueS) \
TEST_SUCCEEDING_CONVERSION( DEF_CONVERTER(typeT,typeS), typeT, typeS, valueT, valueS )
#define TEST_POS_OVERFLOW_CONVERSION_DEF(typeT,typeS,valueS) \
TEST_POS_OVERFLOW_CONVERSION( DEF_CONVERTER(typeT,typeS), typeT, typeS, valueS )
#define TEST_NEG_OVERFLOW_CONVERSION_DEF(typeT,typeS,valueS) \
TEST_NEG_OVERFLOW_CONVERSION( DEF_CONVERTER(typeT,typeS), typeT, typeS, valueS )
//
///////////////////////////////////////////////////////////////////////////////////////////////

View File

@@ -0,0 +1,333 @@
// Copyright (C) 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/cstdint.hpp>
#include <boost/utility.hpp>
#include <boost/preprocessor/cat.hpp>
#include <boost/numeric/conversion/conversion_traits.hpp>
#include <boost/numeric/conversion/int_float_mixture.hpp>
#include <boost/numeric/conversion/sign_mixture.hpp>
#include <boost/numeric/conversion/udt_builtin_mixture.hpp>
#include <boost/numeric/conversion/is_subranged.hpp>
#ifdef BOOST_BORLANDC
#pragma hdrstop
#endif
#include "test_helpers.cpp"
#include "test_helpers2.cpp"
using namespace std ;
using namespace boost ;
using namespace numeric;
using namespace MyUDT ;
// These helpers are used by generate_expected_traits<T,S>.
// Unlike the similar helpers in the implementation, they are specialized by extension.
//
template<class T, class S> struct my_is_subranged ;
template<class T, class S> struct my_is_trivial ;
template<class T, class S> struct my_int_float_mixture ;
template<class T, class S> struct my_sign_mixture ;
template<class T, class S> struct my_udt_builtin_mixture ;
// This macro is used to define the properties of each conversion between
// the builtin arithmetric types
//
// It defines the specialization of the helper traits used by 'generate_expected_traits'
//
#define DEFINE_CONVERSION(Target,Source,Trivial,Mixture,SignMixture,UdtMixture,SubRanged) \
\
template<> struct my_is_subranged<Target,Source> \
{ typedef mpl::bool_< (SubRanged) > type ; } ; \
\
template<> struct my_is_trivial<Target,Source> \
{ typedef mpl::bool_< (Trivial) > type ; } ; \
\
template<> struct my_int_float_mixture<Target,Source> \
{ typedef mpl::integral_c<boost::numeric::int_float_mixture_enum, (Mixture) > type ; } ; \
\
template<> struct my_sign_mixture<Target,Source> \
{ typedef mpl::integral_c<boost::numeric::sign_mixture_enum, (SignMixture) > type ; } ; \
\
template<> struct my_udt_builtin_mixture<Target,Source> \
{ typedef mpl::integral_c<boost::numeric::udt_builtin_mixture_enum, (UdtMixture) > type ; }
#define cSubRanged true
#define cTrivial true
// The following test assumes a specific relation between the sizes of the types being used;
// therefore, use specific fixed-width types instead built-in types directly.
// NOTE --> TARGET,SOURCE
//
DEFINE_CONVERSION(boost::uint8_t , boost::uint8_t, cTrivial, integral_to_integral, unsigned_to_unsigned, builtin_to_builtin, !cSubRanged );
DEFINE_CONVERSION(boost::int8_t , boost::uint8_t, !cTrivial, integral_to_integral, unsigned_to_signed , builtin_to_builtin, cSubRanged );
DEFINE_CONVERSION(boost::uint16_t , boost::uint8_t, !cTrivial, integral_to_integral, unsigned_to_unsigned, builtin_to_builtin, !cSubRanged );
DEFINE_CONVERSION(boost::int16_t , boost::uint8_t, !cTrivial, integral_to_integral, unsigned_to_signed , builtin_to_builtin, !cSubRanged );
DEFINE_CONVERSION(boost::uint32_t , boost::uint8_t, !cTrivial, integral_to_integral, unsigned_to_unsigned, builtin_to_builtin, !cSubRanged );
DEFINE_CONVERSION(boost::int32_t , boost::uint8_t, !cTrivial, integral_to_integral, unsigned_to_signed , builtin_to_builtin, !cSubRanged );
DEFINE_CONVERSION(float , boost::uint8_t, !cTrivial, integral_to_float , unsigned_to_signed , builtin_to_builtin, !cSubRanged );
DEFINE_CONVERSION(double , boost::uint8_t, !cTrivial, integral_to_float , unsigned_to_signed , builtin_to_builtin, !cSubRanged );
DEFINE_CONVERSION(long double , boost::uint8_t, !cTrivial, integral_to_float , unsigned_to_signed , builtin_to_builtin, !cSubRanged );
DEFINE_CONVERSION(MyInt , boost::uint8_t, !cTrivial, integral_to_integral, unsigned_to_signed , builtin_to_udt , !cSubRanged );
DEFINE_CONVERSION(MyFloat , boost::uint8_t, !cTrivial, integral_to_float , unsigned_to_signed , builtin_to_udt , !cSubRanged );
DEFINE_CONVERSION(boost::uint8_t , boost::int8_t, !cTrivial, integral_to_integral, signed_to_unsigned, builtin_to_builtin, cSubRanged );
DEFINE_CONVERSION(boost::int8_t , boost::int8_t, cTrivial, integral_to_integral, signed_to_signed , builtin_to_builtin, !cSubRanged );
DEFINE_CONVERSION(boost::uint16_t , boost::int8_t, !cTrivial, integral_to_integral, signed_to_unsigned, builtin_to_builtin, cSubRanged );
DEFINE_CONVERSION(boost::int16_t , boost::int8_t, !cTrivial, integral_to_integral, signed_to_signed , builtin_to_builtin, !cSubRanged );
DEFINE_CONVERSION(boost::uint32_t , boost::int8_t, !cTrivial, integral_to_integral, signed_to_unsigned, builtin_to_builtin, cSubRanged );
DEFINE_CONVERSION(boost::int32_t , boost::int8_t, !cTrivial, integral_to_integral, signed_to_signed , builtin_to_builtin, !cSubRanged );
DEFINE_CONVERSION(float , boost::int8_t, !cTrivial, integral_to_float , signed_to_signed , builtin_to_builtin, !cSubRanged );
DEFINE_CONVERSION(double , boost::int8_t, !cTrivial, integral_to_float , signed_to_signed , builtin_to_builtin, !cSubRanged );
DEFINE_CONVERSION(long double , boost::int8_t, !cTrivial, integral_to_float , signed_to_signed , builtin_to_builtin, !cSubRanged );
DEFINE_CONVERSION(MyInt , boost::int8_t, !cTrivial, integral_to_integral, signed_to_signed , builtin_to_udt , !cSubRanged );
DEFINE_CONVERSION(MyFloat , boost::int8_t, !cTrivial, integral_to_float , signed_to_signed , builtin_to_udt , !cSubRanged );
DEFINE_CONVERSION(boost::uint8_t , boost::uint16_t, !cTrivial, integral_to_integral, unsigned_to_unsigned, builtin_to_builtin, cSubRanged );
DEFINE_CONVERSION(boost::int8_t , boost::uint16_t, !cTrivial, integral_to_integral, unsigned_to_signed , builtin_to_builtin, cSubRanged );
DEFINE_CONVERSION(boost::uint16_t , boost::uint16_t, cTrivial, integral_to_integral, unsigned_to_unsigned, builtin_to_builtin, !cSubRanged );
DEFINE_CONVERSION(boost::int16_t , boost::uint16_t, !cTrivial, integral_to_integral, unsigned_to_signed , builtin_to_builtin, cSubRanged );
DEFINE_CONVERSION(boost::uint32_t , boost::uint16_t, !cTrivial, integral_to_integral, unsigned_to_unsigned, builtin_to_builtin, !cSubRanged );
DEFINE_CONVERSION(boost::int32_t , boost::uint16_t, !cTrivial, integral_to_integral, unsigned_to_signed , builtin_to_builtin, !cSubRanged );
DEFINE_CONVERSION(float , boost::uint16_t, !cTrivial, integral_to_float , unsigned_to_signed , builtin_to_builtin, !cSubRanged );
DEFINE_CONVERSION(double , boost::uint16_t, !cTrivial, integral_to_float , unsigned_to_signed , builtin_to_builtin, !cSubRanged );
DEFINE_CONVERSION(long double , boost::uint16_t, !cTrivial, integral_to_float , unsigned_to_signed , builtin_to_builtin, !cSubRanged );
DEFINE_CONVERSION(MyInt , boost::uint16_t, !cTrivial, integral_to_integral, unsigned_to_signed , builtin_to_udt , !cSubRanged );
DEFINE_CONVERSION(MyFloat , boost::uint16_t, !cTrivial, integral_to_float , unsigned_to_signed , builtin_to_udt , !cSubRanged );
DEFINE_CONVERSION(boost::uint8_t , boost::int16_t, !cTrivial, integral_to_integral, signed_to_unsigned, builtin_to_builtin, cSubRanged );
DEFINE_CONVERSION(boost::int8_t , boost::int16_t, !cTrivial, integral_to_integral, signed_to_signed , builtin_to_builtin, cSubRanged );
DEFINE_CONVERSION(boost::uint16_t , boost::int16_t, !cTrivial, integral_to_integral, signed_to_unsigned, builtin_to_builtin, cSubRanged );
DEFINE_CONVERSION(boost::int16_t , boost::int16_t, cTrivial, integral_to_integral, signed_to_signed , builtin_to_builtin, !cSubRanged );
DEFINE_CONVERSION(boost::uint32_t , boost::int16_t, !cTrivial, integral_to_integral, signed_to_unsigned, builtin_to_builtin, cSubRanged );
DEFINE_CONVERSION(boost::int32_t , boost::int16_t, !cTrivial, integral_to_integral, signed_to_signed , builtin_to_builtin, !cSubRanged );
DEFINE_CONVERSION(float , boost::int16_t, !cTrivial, integral_to_float , signed_to_signed , builtin_to_builtin, !cSubRanged );
DEFINE_CONVERSION(double , boost::int16_t, !cTrivial, integral_to_float , signed_to_signed , builtin_to_builtin, !cSubRanged );
DEFINE_CONVERSION(long double , boost::int16_t, !cTrivial, integral_to_float , signed_to_signed , builtin_to_builtin, !cSubRanged );
DEFINE_CONVERSION(MyInt , boost::int16_t, !cTrivial, integral_to_integral, signed_to_signed , builtin_to_udt , !cSubRanged );
DEFINE_CONVERSION(MyFloat , boost::int16_t, !cTrivial, integral_to_float , signed_to_signed , builtin_to_udt , !cSubRanged );
DEFINE_CONVERSION(boost::uint8_t , boost::uint32_t, !cTrivial, integral_to_integral, unsigned_to_unsigned, builtin_to_builtin, cSubRanged );
DEFINE_CONVERSION(boost::int8_t , boost::uint32_t, !cTrivial, integral_to_integral, unsigned_to_signed , builtin_to_builtin, cSubRanged );
DEFINE_CONVERSION(boost::uint16_t , boost::uint32_t, !cTrivial, integral_to_integral, unsigned_to_unsigned, builtin_to_builtin, cSubRanged );
DEFINE_CONVERSION(boost::int16_t , boost::uint32_t, !cTrivial, integral_to_integral, unsigned_to_signed , builtin_to_builtin, cSubRanged );
DEFINE_CONVERSION(boost::uint32_t , boost::uint32_t, cTrivial, integral_to_integral, unsigned_to_unsigned, builtin_to_builtin, !cSubRanged );
DEFINE_CONVERSION(boost::int32_t , boost::uint32_t, !cTrivial, integral_to_integral, unsigned_to_signed , builtin_to_builtin, cSubRanged );
DEFINE_CONVERSION(float , boost::uint32_t, !cTrivial, integral_to_float , unsigned_to_signed , builtin_to_builtin, !cSubRanged );
DEFINE_CONVERSION(double , boost::uint32_t, !cTrivial, integral_to_float , unsigned_to_signed , builtin_to_builtin, !cSubRanged );
DEFINE_CONVERSION(long double , boost::uint32_t, !cTrivial, integral_to_float , unsigned_to_signed , builtin_to_builtin, !cSubRanged );
DEFINE_CONVERSION(MyInt , boost::uint32_t, !cTrivial, integral_to_integral, unsigned_to_signed , builtin_to_udt , !cSubRanged );
DEFINE_CONVERSION(MyFloat , boost::uint32_t, !cTrivial, integral_to_float , unsigned_to_signed , builtin_to_udt , !cSubRanged );
DEFINE_CONVERSION(boost::uint8_t , boost::int32_t, !cTrivial, integral_to_integral, signed_to_unsigned, builtin_to_builtin, cSubRanged );
DEFINE_CONVERSION(boost::int8_t , boost::int32_t, !cTrivial, integral_to_integral, signed_to_signed , builtin_to_builtin, cSubRanged );
DEFINE_CONVERSION(boost::uint16_t , boost::int32_t, !cTrivial, integral_to_integral, signed_to_unsigned, builtin_to_builtin, cSubRanged );
DEFINE_CONVERSION(boost::int16_t , boost::int32_t, !cTrivial, integral_to_integral, signed_to_signed , builtin_to_builtin, cSubRanged );
DEFINE_CONVERSION(boost::uint32_t , boost::int32_t, !cTrivial, integral_to_integral, signed_to_unsigned, builtin_to_builtin, cSubRanged );
DEFINE_CONVERSION(boost::int32_t , boost::int32_t, cTrivial, integral_to_integral, signed_to_signed , builtin_to_builtin, !cSubRanged );
DEFINE_CONVERSION(float , boost::int32_t, !cTrivial, integral_to_float , signed_to_signed , builtin_to_builtin, !cSubRanged );
DEFINE_CONVERSION(double , boost::int32_t, !cTrivial, integral_to_float , signed_to_signed , builtin_to_builtin, !cSubRanged );
DEFINE_CONVERSION(long double , boost::int32_t, !cTrivial, integral_to_float , signed_to_signed , builtin_to_builtin, !cSubRanged );
DEFINE_CONVERSION(MyInt , boost::int32_t, !cTrivial, integral_to_integral, signed_to_signed , builtin_to_udt , !cSubRanged );
DEFINE_CONVERSION(MyFloat , boost::int32_t, !cTrivial, integral_to_float , signed_to_signed , builtin_to_udt , !cSubRanged );
DEFINE_CONVERSION(boost::uint8_t , float, !cTrivial, float_to_integral, signed_to_unsigned, builtin_to_builtin, cSubRanged );
DEFINE_CONVERSION(boost::int8_t , float, !cTrivial, float_to_integral, signed_to_signed , builtin_to_builtin, cSubRanged );
DEFINE_CONVERSION(boost::uint16_t , float, !cTrivial, float_to_integral, signed_to_unsigned, builtin_to_builtin, cSubRanged );
DEFINE_CONVERSION(boost::int16_t , float, !cTrivial, float_to_integral, signed_to_signed , builtin_to_builtin, cSubRanged );
DEFINE_CONVERSION(boost::uint32_t , float, !cTrivial, float_to_integral, signed_to_unsigned, builtin_to_builtin, cSubRanged );
DEFINE_CONVERSION(boost::int32_t , float, !cTrivial, float_to_integral, signed_to_signed , builtin_to_builtin, cSubRanged );
DEFINE_CONVERSION(float , float, cTrivial, float_to_float , signed_to_signed , builtin_to_builtin, !cSubRanged );
DEFINE_CONVERSION(double , float, !cTrivial, float_to_float , signed_to_signed , builtin_to_builtin, ( sizeof(float) > sizeof(double) ) );
DEFINE_CONVERSION(long double , float, !cTrivial, float_to_float , signed_to_signed , builtin_to_builtin, ( sizeof(float) > sizeof(long double) ) );
DEFINE_CONVERSION(MyInt , float, !cTrivial, float_to_integral, signed_to_signed , builtin_to_udt , !cSubRanged );
DEFINE_CONVERSION(MyFloat , float, !cTrivial, float_to_float , signed_to_signed , builtin_to_udt , !cSubRanged );
DEFINE_CONVERSION(boost::uint8_t , double, !cTrivial, float_to_integral, signed_to_unsigned, builtin_to_builtin, cSubRanged );
DEFINE_CONVERSION(boost::int8_t , double, !cTrivial, float_to_integral, signed_to_signed , builtin_to_builtin, cSubRanged );
DEFINE_CONVERSION(boost::uint16_t , double, !cTrivial, float_to_integral, signed_to_unsigned, builtin_to_builtin, cSubRanged );
DEFINE_CONVERSION(boost::int16_t , double, !cTrivial, float_to_integral, signed_to_signed , builtin_to_builtin, cSubRanged );
DEFINE_CONVERSION(boost::uint32_t , double, !cTrivial, float_to_integral, signed_to_unsigned, builtin_to_builtin, cSubRanged );
DEFINE_CONVERSION(boost::int32_t , double, !cTrivial, float_to_integral, signed_to_signed , builtin_to_builtin, cSubRanged );
DEFINE_CONVERSION(float , double, !cTrivial, float_to_float , signed_to_signed , builtin_to_builtin, ( sizeof(double) > sizeof(float) ) );
DEFINE_CONVERSION(double , double, cTrivial, float_to_float , signed_to_signed , builtin_to_builtin, !cSubRanged );
DEFINE_CONVERSION(long double , double, !cTrivial, float_to_float , signed_to_signed , builtin_to_builtin, ( sizeof(double) > sizeof(long double) ) );
DEFINE_CONVERSION(MyInt , double, !cTrivial, float_to_integral, signed_to_signed , builtin_to_udt , !cSubRanged );
DEFINE_CONVERSION(MyFloat , double, !cTrivial, float_to_float , signed_to_signed , builtin_to_udt , !cSubRanged );
DEFINE_CONVERSION(boost::uint8_t , long double, !cTrivial, float_to_integral, signed_to_unsigned, builtin_to_builtin, cSubRanged );
DEFINE_CONVERSION(boost::int8_t , long double, !cTrivial, float_to_integral, signed_to_signed , builtin_to_builtin, cSubRanged );
DEFINE_CONVERSION(boost::uint16_t , long double, !cTrivial, float_to_integral, signed_to_unsigned, builtin_to_builtin, cSubRanged );
DEFINE_CONVERSION(boost::int16_t , long double, !cTrivial, float_to_integral, signed_to_signed , builtin_to_builtin, cSubRanged );
DEFINE_CONVERSION(boost::uint32_t , long double, !cTrivial, float_to_integral, signed_to_unsigned, builtin_to_builtin, cSubRanged );
DEFINE_CONVERSION(boost::int32_t , long double, !cTrivial, float_to_integral, signed_to_signed , builtin_to_builtin, cSubRanged );
DEFINE_CONVERSION(float , long double, !cTrivial, float_to_float , signed_to_signed , builtin_to_builtin, ( sizeof(long double) > sizeof(float) ) );
DEFINE_CONVERSION(double , long double, !cTrivial, float_to_float , signed_to_signed , builtin_to_builtin, ( sizeof(long double) > sizeof(double) ) );
DEFINE_CONVERSION(long double , long double, cTrivial, float_to_float , signed_to_signed , builtin_to_builtin, !cSubRanged );
DEFINE_CONVERSION(MyInt , long double, !cTrivial, float_to_integral, signed_to_signed , builtin_to_udt , !cSubRanged );
DEFINE_CONVERSION(MyFloat , long double, !cTrivial, float_to_float , signed_to_signed , builtin_to_udt , !cSubRanged );
DEFINE_CONVERSION(boost::uint8_t , MyInt, !cTrivial, integral_to_integral, signed_to_unsigned, udt_to_builtin , cSubRanged );
DEFINE_CONVERSION(boost::int8_t , MyInt, !cTrivial, integral_to_integral, signed_to_signed , udt_to_builtin , cSubRanged );
DEFINE_CONVERSION(boost::uint16_t , MyInt, !cTrivial, integral_to_integral, signed_to_unsigned, udt_to_builtin , cSubRanged );
DEFINE_CONVERSION(boost::int16_t , MyInt, !cTrivial, integral_to_integral, signed_to_signed , udt_to_builtin , cSubRanged );
DEFINE_CONVERSION(boost::uint32_t , MyInt, !cTrivial, integral_to_integral, signed_to_unsigned, udt_to_builtin , cSubRanged );
DEFINE_CONVERSION(boost::int32_t , MyInt, !cTrivial, integral_to_integral, signed_to_signed , udt_to_builtin , cSubRanged );
DEFINE_CONVERSION(float , MyInt, !cTrivial, integral_to_float , signed_to_signed , udt_to_builtin , cSubRanged );
DEFINE_CONVERSION(double , MyInt, !cTrivial, integral_to_float , signed_to_signed , udt_to_builtin , cSubRanged );
DEFINE_CONVERSION(long double , MyInt, !cTrivial, integral_to_float , signed_to_signed , udt_to_builtin , cSubRanged );
DEFINE_CONVERSION(MyInt , MyInt, cTrivial, integral_to_integral, signed_to_signed , udt_to_udt ,!cSubRanged );
DEFINE_CONVERSION(MyFloat , MyInt, !cTrivial, integral_to_float , signed_to_signed , udt_to_udt ,!cSubRanged );
DEFINE_CONVERSION(boost::uint8_t , MyFloat, !cTrivial, float_to_integral, signed_to_unsigned, udt_to_builtin , cSubRanged );
DEFINE_CONVERSION(boost::int8_t , MyFloat, !cTrivial, float_to_integral, signed_to_signed , udt_to_builtin , cSubRanged );
DEFINE_CONVERSION(boost::uint16_t , MyFloat, !cTrivial, float_to_integral, signed_to_unsigned, udt_to_builtin , cSubRanged );
DEFINE_CONVERSION(boost::int16_t , MyFloat, !cTrivial, float_to_integral, signed_to_signed , udt_to_builtin , cSubRanged );
DEFINE_CONVERSION(boost::uint32_t , MyFloat, !cTrivial, float_to_integral, signed_to_unsigned, udt_to_builtin , cSubRanged );
DEFINE_CONVERSION(boost::int32_t , MyFloat, !cTrivial, float_to_integral, signed_to_signed , udt_to_builtin , cSubRanged );
DEFINE_CONVERSION(float , MyFloat, !cTrivial, float_to_float , signed_to_signed , udt_to_builtin , cSubRanged );
DEFINE_CONVERSION(double , MyFloat, !cTrivial, float_to_float , signed_to_signed , udt_to_builtin , cSubRanged );
DEFINE_CONVERSION(long double , MyFloat, !cTrivial, float_to_float , signed_to_signed , udt_to_builtin , cSubRanged );
DEFINE_CONVERSION(MyInt , MyFloat, !cTrivial, float_to_integral, signed_to_signed , udt_to_udt ,!cSubRanged );
DEFINE_CONVERSION(MyFloat , MyFloat, cTrivial, float_to_float , signed_to_signed , udt_to_udt ,!cSubRanged );
//
// The test is performed by comparing each field of
// boost::numeric::conversion_traits<T,S>
// with the fields of
// expected_traits<T,S>
// which is a traits class constructed explicitely for each combination
// of the built-in arithmetic types.
//
template<class T,
class S,
class Supertype,
class Subtype,
class Subranged,
class Trivial
>
struct expected_traits
{
typedef typename my_int_float_mixture <T,S>::type int_float_mixture ;
typedef typename my_sign_mixture <T,S>::type sign_mixture ;
typedef typename my_udt_builtin_mixture <T,S>::type udt_builtin_mixture ;
typedef Subranged subranged ;
typedef Trivial trivial ;
typedef Supertype supertype ;
typedef Subtype subtype ;
} ;
// This is used by the test engine to generate a expected_traits from T and S.
//
template<class T, class S>
struct generate_expected_traits
{
typedef expected_traits<T, S, T, S, mpl::false_, mpl::true_ > trivial ;
typedef expected_traits<T, S, S, T, mpl::true_ , mpl::false_ > subranged ;
typedef expected_traits<T, S, T, S, mpl::false_, mpl::false_ > non_subranged ;
typedef typename my_is_subranged<T,S>::type IsSubranged ;
typedef typename my_is_trivial <T,S>::type IsTrivial ;
typedef typename mpl::if_<IsSubranged,subranged,non_subranged>::type non_trivial ;
typedef typename mpl::if_<IsTrivial,trivial,non_trivial>::type type ;
} ;
// This macro generates the code that compares a non-type field
// in boost::numeric::conversion_traits<> with its corresponding field
// in expected_traits<>
//
#define TEST_VALUE_FIELD(Name) \
typedef typename traits::Name BOOST_PP_CAT(t,Name) ; \
typedef typename expected::Name BOOST_PP_CAT(x,Name) ; \
BOOST_TEST( ( BOOST_PP_CAT(t,Name)::value == BOOST_PP_CAT(x,Name)::value ) ) ;
// This macro generates the code that compares a type field
// in numeric::conversion_traits<> with its corresponding field
// in expected_traits<>
//
#define TEST_TYPE_FIELD(Name) \
typedef typename traits::Name BOOST_PP_CAT(t,Name) ; \
typedef typename expected::Name BOOST_PP_CAT(x,Name) ; \
BOOST_TEST ( ( typeid(BOOST_PP_CAT(t,Name)) == typeid(BOOST_PP_CAT(x,Name)) ) ) ;
//
// Test core.
// Compares each field of boost::numeric::conversion_traits<T,S>
// with the corresponding field of expected_traits<T,S>
//
template<class T, class S>
void test_traits_base( MATCH_FNTPL_ARG(T), MATCH_FNTPL_ARG(S) )
{
typedef boost::numeric::conversion_traits<T,S> traits ;
typedef typename generate_expected_traits<T,S>::type expected ;
TEST_VALUE_FIELD(int_float_mixture) ;
TEST_VALUE_FIELD(sign_mixture) ;
TEST_VALUE_FIELD(udt_builtin_mixture) ;
TEST_VALUE_FIELD(subranged) ;
TEST_VALUE_FIELD(trivial) ;
TEST_TYPE_FIELD (supertype) ;
TEST_TYPE_FIELD (subtype) ;
}
template<class S>
void test_traits_from( MATCH_FNTPL_ARG(S) )
{
test_traits_base( SET_FNTPL_ARG(boost::uint8_t) ,SET_FNTPL_ARG(S) );
test_traits_base( SET_FNTPL_ARG(boost::int8_t) ,SET_FNTPL_ARG(S) );
test_traits_base( SET_FNTPL_ARG(boost::uint16_t) ,SET_FNTPL_ARG(S) );
test_traits_base( SET_FNTPL_ARG(boost::int16_t) ,SET_FNTPL_ARG(S) );
test_traits_base( SET_FNTPL_ARG(boost::uint32_t) ,SET_FNTPL_ARG(S) );
test_traits_base( SET_FNTPL_ARG(boost::int32_t) ,SET_FNTPL_ARG(S) );
test_traits_base( SET_FNTPL_ARG(float) ,SET_FNTPL_ARG(S) );
test_traits_base( SET_FNTPL_ARG(double) ,SET_FNTPL_ARG(S) );
test_traits_base( SET_FNTPL_ARG(long double) ,SET_FNTPL_ARG(S) );
test_traits_base( SET_FNTPL_ARG(MyInt) ,SET_FNTPL_ARG(S) );
test_traits_base( SET_FNTPL_ARG(MyFloat) ,SET_FNTPL_ARG(S) );
}
void test_traits()
{
test_traits_from( SET_FNTPL_ARG(boost::uint8_t) );
test_traits_from( SET_FNTPL_ARG(boost::int8_t) );
test_traits_from( SET_FNTPL_ARG(boost::uint16_t) );
test_traits_from( SET_FNTPL_ARG(boost::int16_t) );
test_traits_from( SET_FNTPL_ARG(boost::uint32_t) );
test_traits_from( SET_FNTPL_ARG(boost::int32_t) );
test_traits_from( SET_FNTPL_ARG(float) );
test_traits_from( SET_FNTPL_ARG(double) );
test_traits_from( SET_FNTPL_ARG(long double) );
test_traits_from( SET_FNTPL_ARG(MyInt) );
test_traits_from( SET_FNTPL_ARG(MyFloat) );
}
int main()
{
std::cout << std::setprecision( std::numeric_limits<long double>::digits10 ) ;
test_traits();
return boost::report_errors();
}
//---------------------------------------------------------------------------

View File

@@ -0,0 +1,242 @@
// Copyright (C) 2005, 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 "boost/config.hpp"
#include "boost/utility.hpp"
#include "boost/limits.hpp"
#include "boost/utility.hpp"
#include<iostream>
#include<iomanip>
#include<string>
#include<cmath>
#include <boost/core/lightweight_test.hpp>
#include "boost/numeric/conversion/cast.hpp"
using namespace std ;
using namespace boost;
using namespace numeric;
//
// This example illustrates how to add support for user defined types (UDTs)
// to the Boost Numeric Conversion Library.
// It is assumed that you are familiar with the following documentation:
//
//
//
// The minimum requirement is that boost::is_arithmetic<UDT> evaluates to false
// (Otherwise the converter code will try to examine the UDT as a built-in type)
//
//
// Let's start with the simpliest case of an UDT which supports standard conversions
//
struct Double
{
Double( double v ) : mV(v) {}
operator double() const { return mV ; }
double mV ;
} ;
double dv = (numeric_limits<double>::max)() ;
double fv = (numeric_limits<float >::max)() ;
Double Dv(dv);
Double Fv(fv);
void simplest_case()
{
//
// conversion_traits<>::udt_builtin_mixture works out of the box as long as boost::is_arithmetic<UDT> yields false
//
BOOST_TEST( (conversion_traits<double,Double>::udt_builtin_mixture::value == udt_to_builtin) ) ;
BOOST_TEST( (conversion_traits<Double,double>::udt_builtin_mixture::value == builtin_to_udt) ) ;
BOOST_TEST( (conversion_traits<Double,Double>::udt_builtin_mixture::value == udt_to_udt ) ) ;
// BY DEFINITION, a conversion from UDT to Builtin is subranged. No attempt is made to actually compare ranges.
BOOST_TEST( (conversion_traits<double,Double>::subranged::value) == true ) ;
BOOST_TEST( (conversion_traits<Double,double>::subranged::value) == false ) ;
//
// Conversions to/from FLOATING types, if already supported by an UDT
// are also supported out-of-the-box by converter<> in its default configuration.
//
BOOST_TEST( numeric_cast<double>(Dv) == static_cast<double>(Dv) ) ;
BOOST_TEST( numeric_cast<Double>(dv) == static_cast<Double>(dv) ) ;
BOOST_TEST( numeric_cast<float> (Dv) == static_cast<float> (Dv) ) ;
BOOST_TEST( numeric_cast<Double>(fv) == static_cast<Double>(fv) ) ;
//
// Range checking is disabled by default if an UDT is either the source or target of the conversion.
//
BOOST_TEST( (converter<float,double>::out_of_range(dv) == cPosOverflow) );
BOOST_TEST( (converter<float,Double>::out_of_range(Dv) == cInRange) );
}
//
// The conversion_traits<> class and therefore the converter<> class looks at
// numeric_limits<UDT>::is_integer/is_signed to generate the proper float_in and sign mixtures.
// In most implementations, is_integer/is_signed are both false for UDTs if there is no explicit specialization for it.
// Therefore, the converter<> will see any UDT for which numeric_limits<> is not specialized as Float AND unsigned.
// Signess is used in the converter<> for range checking, but range checking is disabled by default for UDTs, so,
// normally, signess is mostly irrelevant as far as the library is concerned, except for the numeric_traits<>::sign_mixture
// entry.
// is_integer, however, is relevant in that if the conversion is from a float type to an integer type, the conversion is
// "rounding" and the rounder policies will participate.
// ALL implemented rounder policies require proper definitions for floor(udt) and ceil(udt).
// These names will be searched for using ADL, so, if you need to convert TO integral types from a UDT,
// you need to supply those functions along with the UDT in right namespace (that is, any namespace that allows
// ADL to find them)
// If your UDT doesn't supply floor/ceil, conversions to integer types
// won't compile unless a custom Float2IntRounder is used.
Double floor ( Double v ) { return Double(std::floor(v.mV)) ; }
Double ceil ( Double v ) { return Double(std::ceil (v.mV)) ; }
void rounding()
{
BOOST_TEST( numeric_cast<int>(Dv) == static_cast<int>(Dv) ) ;
}
//
// If your UDT can't or won't provide floor/ceil you can set-up and use your own
// Float2IntRounder policy (though doing this is not always required as shown so far)
//
struct DoubleToInt
{
static Double nearbyint ( Double const& s ) { return Double(static_cast<int>(s)); }
typedef mpl::integral_c< std::float_round_style, std::round_toward_zero> round_style ;
} ;
void custom_rounding()
{
typedef converter<int
,Double
,conversion_traits<int,Double>
,void // By default UDT disable range checking so this won't be used
,DoubleToInt
>
DoubleToIntConverter ;
BOOST_TEST( DoubleToIntConverter::convert(Dv) == static_cast<int>(Dv) ) ;
}
//
// In the next Level of complexity, your UDTs might not support conversion operators
//
struct Float
{
Float( float v ) : mV(v) {}
float mV ;
} ;
struct Int
{
Int( int v ) : mV(v) {}
int mV ;
} ;
typedef conversion_traits<Int,Float> Float2IntTraits ;
typedef conversion_traits<Float,Int> Int2FloatTraits ;
namespace boost { namespace numeric
{
//
// Though static_cast<> won't work with them you can still use numeric_cast<> by specializing
// raw_converter as follows:
//
template<> struct raw_converter<Float2IntTraits>
{
typedef Float2IntTraits::result_type result_type ;
typedef Float2IntTraits::argument_type argument_type ;
static result_type low_level_convert ( argument_type s ) { return Int((int)s.mV); }
} ;
template<> struct raw_converter<Int2FloatTraits>
{
typedef Int2FloatTraits::result_type result_type ;
typedef Int2FloatTraits::argument_type argument_type ;
static result_type low_level_convert ( argument_type s ) { return Float(s.mV); }
} ;
} }
void custom_raw_converter()
{
Float f (12.34);
Int i (12);
Float fi(12);
BOOST_TEST(numeric_cast<Int> (f).mV == i .mV ) ;
BOOST_TEST(numeric_cast<Float>(i).mV == fi.mV ) ;
}
//
// Alterntively, the custom raw_converter classes can be defined non-instrusively
// (not as specializations) and passed along as policies
//
struct Float2IntRawConverter
{
static Int low_level_convert ( Float const& s ) { return Int((int)s.mV); }
} ;
struct Int2FloatRawConverter
{
static Float low_level_convert ( Int const& s ) { return Float(s.mV); }
} ;
void custom_raw_converter2()
{
Float f (12.34);
Int i (12);
Float fi(12);
typedef converter<Int
,Float
,Float2IntTraits
,void // By default UDT disable range checking so this won't be used
,void // Float2Int Rounder won't be used if Int isn't marked as integer via numeric_limits<>
,Float2IntRawConverter
>
Float2IntConverter ;
BOOST_TEST(Float2IntConverter::convert(f).mV == i .mV ) ;
}
int main()
{
cout << setprecision( numeric_limits<long double>::digits10 ) ;
simplest_case();
rounding();
custom_rounding();
custom_raw_converter();
custom_raw_converter2();
return boost::report_errors();
}

View File

@@ -0,0 +1,309 @@
// (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 BOOST_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 main()
{
cout << setprecision( numeric_limits<long double>::digits10 ) ;
test_udt_conversions_with_defaults();
test_udt_conversions_with_custom_range_checking();
return boost::report_errors();
}