Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:39:13

0001 // Copyright Kevlin Henney, 2000-2005.
0002 // Copyright Alexander Nasonov, 2006-2010.
0003 // Copyright Antony Polukhin, 2011-2023.
0004 //
0005 // Distributed under the Boost Software License, Version 1.0. (See
0006 // accompanying file LICENSE_1_0.txt or copy at
0007 // http://www.boost.org/LICENSE_1_0.txt)
0008 //
0009 // what:  lexical_cast custom keyword cast
0010 // who:   contributed by Kevlin Henney,
0011 //        enhanced with contributions from Terje Slettebo,
0012 //        with additional fixes and suggestions from Gennaro Prota,
0013 //        Beman Dawes, Dave Abrahams, Daryle Walker, Peter Dimov,
0014 //        Alexander Nasonov, Antony Polukhin, Justin Viiret, Michael Hofmann,
0015 //        Cheng Yang, Matthew Bradbury, David W. Birdsall, Pavel Korzh and other Boosters
0016 // when:  November 2000, March 2003, June 2005, June 2006, March 2011 - 2016
0017 
0018 #ifndef BOOST_LEXICAL_CAST_DETAIL_CONVERTER_NUMERIC_HPP
0019 #define BOOST_LEXICAL_CAST_DETAIL_CONVERTER_NUMERIC_HPP
0020 
0021 #include <boost/config.hpp>
0022 #ifdef BOOST_HAS_PRAGMA_ONCE
0023 #   pragma once
0024 #endif
0025 
0026 #include <boost/limits.hpp>
0027 #include <boost/type_traits/type_identity.hpp>
0028 #include <boost/type_traits/conditional.hpp>
0029 #include <boost/type_traits/make_unsigned.hpp>
0030 #include <boost/type_traits/is_signed.hpp>
0031 #include <boost/type_traits/is_integral.hpp>
0032 #include <boost/type_traits/is_arithmetic.hpp>
0033 #include <boost/type_traits/is_base_of.hpp>
0034 #include <boost/type_traits/is_float.hpp>
0035 #include <boost/type_traits/remove_volatile.hpp>
0036 
0037 #include <boost/numeric/conversion/cast.hpp>
0038 
0039 namespace boost { namespace detail {
0040 
0041 template <class Source >
0042 struct detect_precision_loss
0043 {
0044     typedef Source source_type;
0045     typedef boost::numeric::Trunc<Source> Rounder;
0046     typedef typename conditional<
0047         boost::is_arithmetic<Source>::value, Source, Source const&
0048     >::type argument_type ;
0049 
0050     static inline source_type nearbyint(argument_type s, bool& is_ok) noexcept {
0051         const source_type near_int = Rounder::nearbyint(s);
0052         if (near_int && is_ok) {
0053             const source_type orig_div_round = s / near_int;
0054             const source_type eps = std::numeric_limits<source_type>::epsilon();
0055 
0056             is_ok = !((orig_div_round > 1 ? orig_div_round - 1 : 1 - orig_div_round) > eps);
0057         }
0058 
0059         return s;
0060     }
0061 
0062     typedef typename Rounder::round_style round_style;
0063 };
0064 
0065 template <typename Base, class Source>
0066 struct fake_precision_loss: public Base
0067 {
0068     typedef Source source_type ;
0069     typedef typename conditional<
0070         boost::is_arithmetic<Source>::value, Source, Source const&
0071     >::type argument_type ;
0072 
0073     static inline source_type nearbyint(argument_type s, bool& /*is_ok*/) noexcept {
0074         return s;
0075     }
0076 };
0077 
0078 struct nothrow_overflow_handler
0079 {
0080     inline bool operator() ( boost::numeric::range_check_result r ) const noexcept {
0081         return (r == boost::numeric::cInRange);
0082     }
0083 };
0084 
0085 template <typename Target, typename Source>
0086 inline bool noexcept_numeric_convert(const Source& arg, Target& result) noexcept {
0087     typedef boost::numeric::converter<
0088             Target,
0089             Source,
0090             boost::numeric::conversion_traits<Target, Source >,
0091             nothrow_overflow_handler,
0092             detect_precision_loss<Source >
0093     > converter_orig_t;
0094 
0095     typedef typename boost::conditional<
0096         boost::is_base_of< detect_precision_loss<Source >, converter_orig_t >::value,
0097         converter_orig_t,
0098         fake_precision_loss<converter_orig_t, Source>
0099     >::type converter_t;
0100 
0101     bool res = nothrow_overflow_handler()(converter_t::out_of_range(arg));
0102     if (res) {
0103         result = converter_t::low_level_convert(converter_t::nearbyint(arg, res));
0104     }
0105 
0106     return res;
0107 }
0108 
0109 template <typename Target, typename Source>
0110 struct lexical_cast_dynamic_num_not_ignoring_minus
0111 {
0112     static inline bool try_convert(const Source &arg, Target& result) noexcept {
0113         return noexcept_numeric_convert<Target, Source >(arg, result);
0114     }
0115 };
0116 
0117 template <typename Target, typename Source>
0118 struct lexical_cast_dynamic_num_ignoring_minus
0119 {
0120     static inline bool try_convert(const Source &arg, Target& result) noexcept {
0121         typedef typename boost::conditional<
0122                 boost::is_float<Source>::value,
0123                 boost::type_identity<Source>,
0124                 boost::make_unsigned<Source>
0125         >::type usource_lazy_t;
0126         typedef typename usource_lazy_t::type usource_t;
0127 
0128         if (arg < 0) {
0129             const bool res = noexcept_numeric_convert<Target, usource_t>(0u - arg, result);
0130             result = static_cast<Target>(0u - result);
0131             return res;
0132         } else {
0133             return noexcept_numeric_convert<Target, usource_t>(arg, result);
0134         }
0135     }
0136 };
0137 
0138 /*
0139  * lexical_cast_dynamic_num follows the rules:
0140  * 1) If Source can be converted to Target without precision loss and
0141  * without overflows, then assign Source to Target and return
0142  *
0143  * 2) If Source is less than 0 and Target is an unsigned integer,
0144  * then negate Source, check the requirements of rule 1) and if
0145  * successful, assign static_casted Source to Target and return
0146  *
0147  * 3) Otherwise throw a bad_lexical_cast exception
0148  *
0149  *
0150  * Rule 2) required because boost::lexical_cast has the behavior of
0151  * stringstream, which uses the rules of scanf for conversions. And
0152  * in the C99 standard for unsigned input value minus sign is
0153  * optional, so if a negative number is read, no errors will arise
0154  * and the result will be the two's complement.
0155  */
0156 template <typename Target, typename Source>
0157 struct dynamic_num_converter_impl
0158 {
0159     typedef typename boost::remove_volatile<Source>::type source_type;
0160 
0161     static inline bool try_convert(source_type arg, Target& result) noexcept {
0162         typedef typename boost::conditional<
0163             boost::is_unsigned<Target>::value &&
0164             (boost::is_signed<source_type>::value || boost::is_float<source_type>::value) &&
0165             !(boost::is_same<source_type, bool>::value) &&
0166             !(boost::is_same<Target, bool>::value),
0167             lexical_cast_dynamic_num_ignoring_minus<Target, source_type>,
0168             lexical_cast_dynamic_num_not_ignoring_minus<Target, source_type>
0169         >::type caster_type;
0170 
0171         return caster_type::try_convert(arg, result);
0172     }
0173 };
0174 
0175 }} // namespace boost::detail
0176 
0177 #endif // BOOST_LEXICAL_CAST_DETAIL_CONVERTER_NUMERIC_HPP
0178