123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448 |
- [/
- Boost.Optional
- Copyright (c) 2003-2007 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)
- ]
- [section Type Requirements and User-defined-types support]
- [section Type Requirements]
- Both arithmetic (built-in) and user-defined numeric types require proper
- specialization of `std::numeric_limits<>` (that is, with (in-class) integral
- constants).
- The library uses `std::numeric_limits<T>::is_specialized` to detect whether
- the type is builtin or user defined, and `std::numeric_limits<T>::is_integer`,
- `std::numeric_limits<T>::is_signed` to detect whether the type is integer
- or floating point; and whether it is signed/unsigned.
- The default `Float2IntRounder` policies uses unqualified calls to functions
- `floor()` and `ceil()`; but the standard functions are introduced in scope
- by a using directive:
- using std::floor ; return floor(s);
- Therefore, for builtin arithmetic types, the std functions will be used.
- User defined types should provide overloaded versions of these functions in
- order to use the default rounder policies. If these overloads are defined
- within a user namespace argument dependent lookup (ADL) should find them,
- but if your compiler has a weak ADL you might need to put these functions
- some place else or write your own rounder policy.
- The default `Trunc<>` rounder policy needs to determine if the source value
- is positive or not, and for this it evaluates the expression
- `s < static_cast<S>(0)`. Therefore, user defined types require a visible
- `operator<` in order to use the `Trunc<>` policy (the default).
- [endsect]
- [section UDT's special semantics]
- [heading Conversion Traits]
- If a User Defined Type is involved in a conversion, it is ['assumed] that
- the UDT has [link boost_numericconversion.definitions.range_and_precision wider range]
- than any built-in type, and consequently the values
- of some `converter_traits<>` members are hardwired regardless of the reality.
- The following table summarizes this:
- * `Target=`['UDT] and `Source=`['built-in]
- * `subranged=false`
- * `supertype=Target`
- * `subtype=Source`
- * `Target=`['built-in] and `Source=`['UDT]
- * `subranged=true`
- * `supertype=Source`
- * `subtype=Target`
- * `Target=`['UDT] and `Source=`['UDT]
- * `subranged=false`
- * `supertype=Target`
- * `subtype=Source`
- The `Traits` member `udt_mixture` can be used to detect whether a UDT is involved
- and to infer the validity of the other members as shown above.
- [heading Range Checking]
- Because User Defined Numeric Types might have peculiar ranges (such as an
- unbounded range), this library does not attempt to supply a meaningful range
- checking logic when UDTs are involved in a conversion. Therefore, if either
- Target or Source are not built-in types, the bundled range checking of the
- `converter<>` function object is automatically disabled. However, it is possible
- to supply a user-defined range-checker. See
- [link boost_numericconversion.type_requirements_and_user_defined_types_support.special_policies Special Policies]
- [endsect]
- [section Special Policies]
- There are two components of the `converter<>` class that might require special
- behavior if User Defined Numeric Types are involved: the Range Checking and the
- Raw Conversion.
- When both Target and Source are built-in types, the converter class uses an internal
- range checking logic which is optimized and customized for the combined properties
- of the types.
- However, this internal logic is disabled when either type is User Defined.
- In this case, the user can specify an ['external] range checking policy which will be
- used in place of the internal code. See
- [link boost_numericconversion.type_requirements_and_user_defined_types_support.udts_with_numeric_cast numeric_cast_traits]
- for details on using UDTs with `numeric_cast`.
- The converter class performs the actual conversion using a Raw Converter policy.
- The default raw converter simply performs a `static_cast<Target>(source)`.
- However, if the a UDT is involved, the `static_cast` might not work. In this case,
- the user can implement and pass a different raw converter policy.
- See [link boost_numericconversion.numeric_converter_policy_classes.policy_rawconverter RawConverter] policy for details.
- [endsect]
- [section UDTs with numeric_cast]
- In order to employ UDTs with `numeric_cast`, the user should define
- a `numeric_cast_traits` specialization on the UDT for each conversion.
- Here is an example of specializations for converting between the UDT
- and any other type:
- namespace boost { namespace numeric {
- template <typename Source>
- struct numeric_cast_traits<UDT, Source>
- {
- typedef conversion_traits<UDT, Source> conv_traits;
-
- //! The following are required:
- typedef YourOverflowHandlerPolicy overflow_policy;
- typedef YourRangeCheckerPolicy<conv_traits> range_checking_policy;
- typedef YourFloat2IntRounderPolicy<Source> rounding_policy;
- };
- template <typename Target>
- struct numeric_cast_traits<Target, UDT>
- {
- typedef conversion_traits<Target, UDT> conv_traits;
-
- //! The following are required:
- typedef YourOverflowHandlerPolicy overflow_policy;
- typedef YourRangeCheckerPolicy<conv_traits> range_checking_policy;
- typedef YourFloat2IntRounderPolicy<UDT> rounding_policy;
- };
- }}//namespace boost::numeric;
- These specializations are already defined with default values for the built-in
- numeric types. It is possible to disable the generation of specializations for
- built-in types by defining `BOOST_NUMERIC_CONVERSION_RELAX_BUILT_IN_CAST_TRAITS`.
- For details on defining custom policies see [link boost_numericconversion.numeric_converter_policy_classes Converter Policies].
- Here is a full example of how to define a custom UDT for use with `numeric_cast`:
- //! Define a simple custom number
- struct Double
- : boost::ordered_field_operators
- <
- Double
- , boost::ordered_field_operators2< Double, long double
- , boost::ordered_field_operators2< Double, double
- , boost::ordered_field_operators2< Double, float
- , boost::ordered_field_operators2< Double, int
- , boost::ordered_field_operators2< Double, unsigned int
- , boost::ordered_field_operators2< Double, long
- , boost::ordered_field_operators2< Double, unsigned long
- , boost::ordered_field_operators2< Double, long long
- , boost::ordered_field_operators2< Double, unsigned long long
- , boost::ordered_field_operators2< Double, char
- , boost::ordered_field_operators2< Double, unsigned char
- , boost::ordered_field_operators2< Double, short
- , boost::ordered_field_operators2< Double, unsigned short
- > > > > > > > > > > > > > >
- {
- 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);
- }
- bool operator > ( const Double& rhs ) const
- {
- return v > 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);
- }
-
- 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;
-
- [endsect]
- [endsect]
|