diff options
Diffstat (limited to 'src/boost/libs/numeric/conversion')
15 files changed, 2589 insertions, 0 deletions
diff --git a/src/boost/libs/numeric/conversion/README.md b/src/boost/libs/numeric/conversion/README.md new file mode 100644 index 00000000..987f0ecf --- /dev/null +++ b/src/boost/libs/numeric/conversion/README.md @@ -0,0 +1,8 @@ +# Boost.NumericConversion + +The Boost Numeric Conversion library is a collection of tools to describe and perform conversions between values of different [numeric types][1]. + +The documentation for the library can be found [here][2] + +[1]: http://www.boost.org/doc/libs/release/libs/numeric/conversion/doc/html/boost_numericconversion/definitions.html#boost_numericconversion.definitions.numeric_types +[2]: http://www.boost.org/doc/libs/release/libs/numeric/conversion/doc/html/index.html#numeric_conversion.overview diff --git a/src/boost/libs/numeric/conversion/index.html b/src/boost/libs/numeric/conversion/index.html new file mode 100644 index 00000000..305b7385 --- /dev/null +++ b/src/boost/libs/numeric/conversion/index.html @@ -0,0 +1,13 @@ +<html> +<head> +<meta http-equiv="refresh" content="0; URL=doc/html/index.html"> +</head> +<body> +Automatic redirection failed, please go to +<a href="doc/html/index.html">doc/index.html</a>. <hr> +<p>� Copyright Beman Dawes, 2001</p> +<p>Distributed under the Boost Software License, Version 1.0. (See accompanying +file <a href="../../../LICENSE_1_0.txt">LICENSE_1_0.txt</a> or copy +at <a href="http://www.boost.org/LICENSE_1_0.txt">www.boost.org/LICENSE_1_0.txt</a>)</p> +</body> +</html> diff --git a/src/boost/libs/numeric/conversion/meta/libraries.json b/src/boost/libs/numeric/conversion/meta/libraries.json new file mode 100644 index 00000000..945591c8 --- /dev/null +++ b/src/boost/libs/numeric/conversion/meta/libraries.json @@ -0,0 +1,16 @@ +{ + "key": "numeric/conversion", + "name": "Numeric Conversion", + "authors": [ + "Fernando Cacciola" + ], + "description": "Optimized Policy-based Numeric Conversions.", + "category": [ + "Math", + "Miscellaneous" + ], + "maintainers": [ + "Fernando Cacciola <fernando_cacciola -at- ciudad.com.ar>", + "Brandon Kohn <blkohn -at- hotmail.com>" + ] +} diff --git a/src/boost/libs/numeric/conversion/test/Jamfile.v2 b/src/boost/libs/numeric/conversion/test/Jamfile.v2 new file mode 100644 index 00000000..16f3eba3 --- /dev/null +++ b/src/boost/libs/numeric/conversion/test/Jamfile.v2 @@ -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 ; diff --git a/src/boost/libs/numeric/conversion/test/bounds_test.cpp b/src/boost/libs/numeric/conversion/test/bounds_test.cpp new file mode 100644 index 00000000..504c47c5 --- /dev/null +++ b/src/boost/libs/numeric/conversion/test/bounds_test.cpp @@ -0,0 +1,101 @@ +// (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 __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_CHECK_MESSAGE ( lowest == expected_lowest, + "bounds<" << typeid(T).name() << ">::lowest() = " << printable(lowest) << ". Expected " << printable(expected_lowest) + ) ; + + BOOST_CHECK_MESSAGE ( highest == expected_highest, + "bounds<" << typeid(T).name() << ">::highest() = " << printable(highest) << ". Expected " << printable(expected_highest) + ) ; + + BOOST_CHECK_MESSAGE ( smallest == expected_smallest, + "bounds<" << typeid(T).name() << ">::smallest() = " << printable(smallest) << ". Expected " << printable(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 test_main( int, char * [] ) +{ + cout << setprecision( std::numeric_limits<long double>::digits10 ) ; + + test_bounds(); + + return 0; +} + diff --git a/src/boost/libs/numeric/conversion/test/compile_fail/built_in_numeric_cast_traits.cpp b/src/boost/libs/numeric/conversion/test/compile_fail/built_in_numeric_cast_traits.cpp new file mode 100644 index 00000000..c795d88b --- /dev/null +++ b/src/boost/libs/numeric/conversion/test/compile_fail/built_in_numeric_cast_traits.cpp @@ -0,0 +1,122 @@ +// +//! 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> +#include <boost/test/minimal.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; + +int test_main( int argc, char * argv[] ) +{ + //! This test should not compile. + return 1; +} + +#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 diff --git a/src/boost/libs/numeric/conversion/test/converter_test.cpp b/src/boost/libs/numeric/conversion/test/converter_test.cpp new file mode 100644 index 00000000..a460df15 --- /dev/null +++ b/src/boost/libs/numeric/conversion/test/converter_test.cpp @@ -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(__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 __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_CHECK( 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_CHECK_MESSAGE(double_to_int_OK, "converter (int,double) as function object"); + + // 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_CHECK_MESSAGE(double_to_double_OK, "converter (double,double) as function object"); +} + +#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 test_main( int, char* argv[] ) +{ + 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 0; +} +//--------------------------------------------------------------------------- + diff --git a/src/boost/libs/numeric/conversion/test/numeric_cast_test.cpp b/src/boost/libs/numeric/conversion/test/numeric_cast_test.cpp new file mode 100644 index 00000000..f94393cb --- /dev/null +++ b/src/boost/libs/numeric/conversion/test/numeric_cast_test.cpp @@ -0,0 +1,97 @@ +// 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/test/minimal.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 test_main( int argc, char * argv[] ) +{ + +# 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_CHECK( c == 1 ); + c = 0; + c = numeric_cast<signed char>( small_value ); + BOOST_CHECK( c == 1 ); + c = 0; + c = numeric_cast<signed char>( small_negative_value ); + BOOST_CHECK( c == -1 ); + + // These tests courtesy of Joe R NWP Swatosh<joe.r.swatosh@usace.army.mil> + BOOST_CHECK( 0.0f == numeric_cast<float>( 0.0 ) ); + BOOST_CHECK( 0.0 == numeric_cast<double>( 0.0 ) ); + + // tests which should result in errors being detected + + bool caught_exception = false; + try { c = numeric_cast<signed char>( large_value ); } + catch ( numeric::bad_numeric_cast ) + { cout<<"caught bad_numeric_cast #1\n"; caught_exception = true; } + BOOST_CHECK ( caught_exception ); + + caught_exception = false; + try { c = numeric_cast<signed char>( large_negative_value ); } + catch ( numeric::bad_numeric_cast ) + { cout<<"caught bad_numeric_cast #2\n"; caught_exception = true; } + BOOST_CHECK ( caught_exception ); + + unsigned long ul; + caught_exception = false; + try { ul = numeric_cast<unsigned long>( large_negative_value ); } + catch ( numeric::bad_numeric_cast ) + { cout<<"caught bad_numeric_cast #3\n"; caught_exception = true; } + BOOST_CHECK ( caught_exception ); + + caught_exception = false; + try { ul = numeric_cast<unsigned long>( small_negative_value ); } + catch ( numeric::bad_numeric_cast ) + { cout<<"caught bad_numeric_cast #4\n"; caught_exception = true; } + BOOST_CHECK ( caught_exception ); + + caught_exception = false; + try { numeric_cast<int>( DBL_MAX ); } + catch ( numeric::bad_numeric_cast ) + { cout<<"caught bad_numeric_cast #5\n"; caught_exception = true; } + BOOST_CHECK ( caught_exception ); + + return 0 ; + +} // main diff --git a/src/boost/libs/numeric/conversion/test/numeric_cast_traits_test.cpp b/src/boost/libs/numeric/conversion/test/numeric_cast_traits_test.cpp new file mode 100644 index 00000000..f59cb6bc --- /dev/null +++ b/src/boost/libs/numeric/conversion/test/numeric_cast_traits_test.cpp @@ -0,0 +1,380 @@ +// +//! 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 diff --git a/src/boost/libs/numeric/conversion/test/test_helpers.cpp b/src/boost/libs/numeric/conversion/test/test_helpers.cpp new file mode 100644 index 00000000..5f2d88d3 --- /dev/null +++ b/src/boost/libs/numeric/conversion/test/test_helpers.cpp @@ -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/test/included/test_exec_monitor.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(__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 ; } + + +// +/////////////////////////////////////////////////////////////////////////////////////////////// + diff --git a/src/boost/libs/numeric/conversion/test/test_helpers2.cpp b/src/boost/libs/numeric/conversion/test/test_helpers2.cpp new file mode 100644 index 00000000..8fca50b6 --- /dev/null +++ b/src/boost/libs/numeric/conversion/test/test_helpers2.cpp @@ -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!)" ; +} + +// +/////////////////////////////////////////////////////////////////////////////////////////////// + diff --git a/src/boost/libs/numeric/conversion/test/test_helpers3.cpp b/src/boost/libs/numeric/conversion/test/test_helpers3.cpp new file mode 100644 index 00000000..de345ba8 --- /dev/null +++ b/src/boost/libs/numeric/conversion/test/test_helpers3.cpp @@ -0,0 +1,144 @@ +// 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 ( conv.post == c_converted ) + { + BOOST_CHECK_MESSAGE( result == conv.result, + conv.to_string() << printable(source) << ")= " << printable(result) << ". Expected:" << printable(conv.result) + ) ; + } + else + { + BOOST_ERROR( conv.to_string() << printable(source) << ") = " << printable(result) + << ". Expected:" << ( conv.post == c_neg_overflow ? " negative_overflow" : "positive_overflow" ) + ) ; + } + } + catch ( boost::numeric::negative_overflow const& ) + { + if ( conv.post == c_neg_overflow ) + { + BOOST_CHECK_MESSAGE( true, conv.to_string() << printable(source) << ") = negative_overflow, as expected" ) ; + } + else + { + BOOST_ERROR( conv.to_string() << printable(source) << ") = negative_overflow. Expected:" << printable(conv.result) ) ; + } + } + catch ( boost::numeric::positive_overflow const& ) + { + if ( conv.post == c_pos_overflow ) + { + BOOST_CHECK_MESSAGE( true, conv.to_string() << printable(source) << ") = positive_overflow, as expected" ) ; + } + else + { + BOOST_ERROR( conv.to_string() << printable(source) << ") = positive_overflow. Expected:" << printable(conv.result) ) ; + } + } + catch ( boost::numeric::bad_numeric_cast const& ) + { + if ( conv.post == c_overflow ) + { + BOOST_CHECK_MESSAGE( true, conv.to_string() << printable(source) << ") = bad_numeric_cast, as expected" ) ; + } + else + { + BOOST_ERROR( conv.to_string() << printable(source) << ") = bad_numeric_cast. Expected:" << printable(conv.result) ) ; + } + } +} + + +#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 ) + + +// +/////////////////////////////////////////////////////////////////////////////////////////////// + diff --git a/src/boost/libs/numeric/conversion/test/traits_test.cpp b/src/boost/libs/numeric/conversion/test/traits_test.cpp new file mode 100644 index 00000000..d8d620b7 --- /dev/null +++ b/src/boost/libs/numeric/conversion/test/traits_test.cpp @@ -0,0 +1,341 @@ +// 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 __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_CHECK_MESSAGE ( ( BOOST_PP_CAT(t,Name)::value == BOOST_PP_CAT(x,Name)::value ) , \ + "conversion_traits<" << typeid(T).name() << "," << typeid(S).name() \ + << ">::" << #Name << " = " << to_string(BOOST_PP_CAT(t,Name)::value) \ + << ". Expected: " << to_string(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_CHECK_MESSAGE ( ( typeid(BOOST_PP_CAT(t,Name)) == typeid(BOOST_PP_CAT(x,Name)) ) , \ + "conversion_traits<" << typeid(T).name() << "," << typeid(S).name() \ + << ">::" << #Name << " = " << typeid(BOOST_PP_CAT(t,Name)).name() \ + << ". Expected: " << typeid(BOOST_PP_CAT(x,Name)).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 test_main( int, char * []) +{ + std::cout << std::setprecision( std::numeric_limits<long double>::digits10 ) ; + + test_traits(); + + return 0; +} +//--------------------------------------------------------------------------- + diff --git a/src/boost/libs/numeric/conversion/test/udt_example_0.cpp b/src/boost/libs/numeric/conversion/test/udt_example_0.cpp new file mode 100644 index 00000000..067e5e7a --- /dev/null +++ b/src/boost/libs/numeric/conversion/test/udt_example_0.cpp @@ -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/test/included/test_exec_monitor.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_CHECK( (conversion_traits<double,Double>::udt_builtin_mixture::value == udt_to_builtin) ) ; + BOOST_CHECK( (conversion_traits<Double,double>::udt_builtin_mixture::value == builtin_to_udt) ) ; + BOOST_CHECK( (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_CHECK( (conversion_traits<double,Double>::subranged::value) == true ) ; + BOOST_CHECK( (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_CHECK( numeric_cast<double>(Dv) == static_cast<double>(Dv) ) ; + BOOST_CHECK( numeric_cast<Double>(dv) == static_cast<Double>(dv) ) ; + + BOOST_CHECK( numeric_cast<float> (Dv) == static_cast<float> (Dv) ) ; + BOOST_CHECK( 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_CHECK( (converter<float,double>::out_of_range(dv) == cPosOverflow) ); + BOOST_CHECK( (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_CHECK( 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_CHECK( 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_CHECK(numeric_cast<Int> (f).mV == i .mV ) ; + BOOST_CHECK(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_CHECK(Float2IntConverter::convert(f).mV == i .mV ) ; +} + +int test_main( int, char* [] ) +{ + cout << setprecision( numeric_limits<long double>::digits10 ) ; + + simplest_case(); + rounding(); + custom_rounding(); + custom_raw_converter(); + custom_raw_converter2(); + + return 0; +} + + + + + + diff --git a/src/boost/libs/numeric/conversion/test/udt_support_test.cpp b/src/boost/libs/numeric/conversion/test/udt_support_test.cpp new file mode 100644 index 00000000..581b0e50 --- /dev/null +++ b/src/boost/libs/numeric/conversion/test/udt_support_test.cpp @@ -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 __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; +} + + + + + + |