//@doc///////////////////////////////////////////////////////////////////////////////////////// // // SIERRA S.R.L. - Tecnología y Servicio - Departamento de Software. // //============================================================================================= // Generic Numeric Conversion. Fernando Cacciola. // // 23/06/2000 FLC Initial build. // 28/06/2000 FLC range code move to numeric_bounds.h // #ifndef __RTL_CVT_N_H_ #define __RTL_CVT_N_H_ #include "numeric_bounds.h" #define NO_STATIC_COVARIANT // cvt_traits is used for the 'return type optimization'. // When the conversion is performed between equal types, the return type is // just a reference to the parameter, allowing the compiler to completely // bypass the conversion. template struct cvt_traits { typedef T ret_type ; } ; template struct cvt_traits { typedef S const& ret_type ; } ; namespace gmath { //---------------------------------------------------------------------------------------- // This auxiliary function throws an exception in the case of an out of range. // It recieves the original value 's' and returns a value of type T. // For a given pair T,S, this can be specialized so that some value of type T is // returned, perhaps a closer match. // By default, a cvt_range_error() exception is thrown (see below). // //---------------------------------------------------------------------------------------- // cvt_range_error // This exception class contains all the information about the types and values // being converted. // It has a record of the typenames of T and S and of their actual values. // struct cvt_range_error : std::range_error { struct values_base { values_base ( std::string const& t_typename_ , std::string const& s_typename_ ) : t_typename(t_typename_), s_typename(s_typename_), refs (0) {} virtual ~ values_base(){} std::string t_typename ; std::string s_typename ; int refs ; } ; template struct values_impl : values_base { values_impl ( T const& _t , S const& _s ) : values_base ( typeid(_t).name() , typeid(_s).name() ) , t ( _t ) , s ( _s ) {} T t ; S s ; } ; template cvt_range_error ( std::string const& msg , S const& s , T const& t ) : std::range_error(msg) , values ( new values_impl ( t , s ) ) { values->refs ++ ; } cvt_range_error ( cvt_range_error const& rhs ) : std::range_error ( rhs ) , values ( rhs.values) { values->refs ++ ; } ~ cvt_range_error() { if ( -- values->refs == 0 ) delete values ; } values_base* values; } ; //---------------------------------------------------------------------------------------- template T cvt_out_of_range_error( S const& s , int sign ) { T t = sign == -1 ? numeric_bounds::lowest() : numeric_bounds::highest() ; throw cvt_range_error( "out-of-range conversion" , s , t ) ; } //---------------------------------------------------------------------------------------- // The following identifiers are implementation specific, thus they are hidden in // a private namespace. namespace cvt_n_aux { // IMPLEMENTATION NOTE: // The explicit casts throughout this code are needed to tell the compiler // that a lose of precision is ok. Without them, most compilers will yield the // warning: 'convertion might lose significant digits' // ret_traits is used for the 'return type optimization'. // When the conversion is performed between equal types, the return type is // just a reference to the parameter, allowing the compiler to completely // bypass the conversion. template struct ret_traits { typedef T type ; } ; template struct ret_traits { typedef S const& type ; } ; // Inner conversion procedure. template struct convert { // By default(check_range=false) just call Round() and cast the result. template static ret_traits::type cvt ( S const& s , rounder Round ) { int sg = numeric_bounds_comparison::test(s) ; if ( sg != 0 ) return (ret_traits::type)cvt_out_of_range_error(s,sg); else return (ret_traits::type)Round(s) ; } } ; // rounding_dispatch template struct rounding_dispatch {} ; // rounding_dispatch specialization for rounding conversions. template struct rounding_dispatch { // round is a free template function declared above. static S round_it ( S const& s ) { return round(s) ; } static ret_traits::type cvt ( S const& s ) { return convert::cvt(s,round_it) ; } } ; // rounding_dispatch specialization for non-rounding conversions. template struct rounding_dispatch { // round is a free template function declared above. static S const& not_round_it ( S const& s ) { return s ; } static ret_traits::type cvt ( S const& s ) { return convert::cvt(s,not_round_it) ; } } ; // main_dispatch. // cvt implementation for T!=S template struct main_dispatch { static ret_traits::type cvt ( S const& s ) { return rounding_dispatch::is_integer && !std::numeric_limits::is_integer >::cvt(s); } } ; // main_dispatch. // cvt implementation for T==S. template struct main_dispatch { // ret_traits::type is expanded to S const& so this is effectively // bypassed. static ret_traits::type cvt ( S const& s ) { return s ; } } ; } // namespace cvt_n_aux ////////////////////////////////////////////////////////////////////////////////////////// // // T t = cvt_n(s) // // Converts from numeric S to numeric T. // The following optimizations are performed: // // 1) Conversion between equal types are effectively bypassed. // S v ; S u = cvt_n(v) ; // Expands to: S u = v ; // // 2) Range checking is applied, but is controlled by a traits. // For built-in types, range checking is bypassed if convertion goes to // a bigger range type: // int u = cvt_n( (short) 1 ) ; // No range checking. // // Mixing signed/unsigned types forces range checking: // // int u = cvt_n ( (unsigned int) 1) ; // range checking. // // 3) Rounding is applied when converting from a non-integer type to an // integer type (in other cases rounding is not applied). // The rounding is performed by a free template function round() which can // be specialized. // Range checking is combined to ensure proper conversion after rounding. // // int u = cvt_n(2.5) ; // rounding and range checking. // float v = cvt_n and // provides applicable constructors and conversion operators. // template inline cvt_n_aux::ret_traits::type cvt_n ( S const& s ) { // A template dispatch engine selects the apropriate implementations according // to the properties of S and T. return cvt_n_aux::main_dispatch::cvt(s); } } //namespace gmath. using gmath::cvt_n ; #endif // ///////////////////////////////////////////////////////////////////////////////////////////////