Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-07-06 08:17:56

0001 // Copyright Kevlin Henney, 2000-2005.
0002 // Copyright Alexander Nasonov, 2006-2010.
0003 // Copyright Antony Polukhin, 2011-2024.
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/core/cmath.hpp>
0027 #include <boost/core/enable_if.hpp>
0028 #include <boost/limits.hpp>
0029 #include <boost/type_traits/type_identity.hpp>
0030 #include <boost/type_traits/conditional.hpp>
0031 #include <boost/type_traits/make_unsigned.hpp>
0032 #include <boost/type_traits/is_signed.hpp>
0033 #include <boost/type_traits/is_arithmetic.hpp>
0034 #include <boost/type_traits/is_float.hpp>
0035 
0036 namespace boost { namespace detail {
0037 
0038 template <class Source, class Target>
0039 bool ios_numeric_comparer_float(Source x, Source y) noexcept {
0040     return x == y
0041         || (boost::core::isnan(x) && boost::core::isnan(y))
0042         || (x < (std::numeric_limits<Target>::min)())
0043     ;
0044 }
0045 
0046 template <class RangeType, class T>
0047 constexpr bool is_out_of_range_for(T value) noexcept {
0048     return value > static_cast<T>((std::numeric_limits<RangeType>::max)())
0049         || value < static_cast<T>((std::numeric_limits<RangeType>::min)());
0050 }
0051 
0052 
0053 // integral -> integral
0054 template <typename Target, typename Source>
0055 typename boost::enable_if_c<
0056     !boost::is_floating_point<Source>::value && !boost::is_floating_point<Target>::value, bool
0057 >::type noexcept_numeric_convert(Source arg, Target& result) noexcept {
0058     const Target target_tmp = static_cast<Target>(arg);
0059     const Source arg_restored = static_cast<Source>(target_tmp);
0060     if (arg == arg_restored) {
0061         result = target_tmp;
0062         return true;
0063     }
0064     return false;
0065 }
0066 
0067 // integral -> floating point
0068 template <typename Target, typename Source>
0069 typename boost::enable_if_c<
0070     !boost::is_floating_point<Source>::value && boost::is_floating_point<Target>::value, bool
0071 >::type noexcept_numeric_convert(Source arg, Target& result) noexcept {
0072     const Target target_tmp = static_cast<Target>(arg);
0073     result = target_tmp;
0074     return true;
0075 }
0076 
0077 
0078 // floating point -> floating point
0079 template <typename Target, typename Source>
0080 typename boost::enable_if_c<
0081     boost::is_floating_point<Source>::value && boost::is_floating_point<Target>::value, bool
0082 >::type noexcept_numeric_convert(Source arg, Target& result) noexcept {
0083     const Target target_tmp = static_cast<Target>(arg);
0084     const Source arg_restored = static_cast<Source>(target_tmp);
0085     if (detail::ios_numeric_comparer_float<Source, Target>(arg, arg_restored)) {
0086         result = target_tmp;
0087         return true;
0088     }
0089 
0090     return false;
0091 }
0092 
0093 // floating point -> integral
0094 template <typename Target, typename Source>
0095 typename boost::enable_if_c<
0096     boost::is_floating_point<Source>::value && !boost::is_floating_point<Target>::value, bool
0097 >::type noexcept_numeric_convert(Source arg, Target& result) noexcept {
0098     if (detail::is_out_of_range_for<Target>(arg)) {
0099         return false;
0100     }
0101 
0102     const Target target_tmp = static_cast<Target>(arg);
0103     const Source arg_restored = static_cast<Source>(target_tmp);
0104     if (detail::ios_numeric_comparer_float<Source, Target>(arg, arg_restored)) {
0105         result = target_tmp;
0106         return true;
0107     }
0108 
0109     return false;
0110 }
0111 
0112 struct lexical_cast_dynamic_num_not_ignoring_minus
0113 {
0114     template <typename Target, typename Source>
0115     static inline bool try_convert(Source arg, Target& result) noexcept {
0116         return boost::detail::noexcept_numeric_convert<Target, Source >(arg, result);
0117     }
0118 };
0119 
0120 struct lexical_cast_dynamic_num_ignoring_minus
0121 {
0122     template <typename Target, typename Source>
0123 #if defined(__clang__) && (__clang_major__ > 3 || __clang_minor__ > 6)
0124     __attribute__((no_sanitize("unsigned-integer-overflow")))
0125 #endif
0126     static inline bool try_convert(Source arg, Target& result) noexcept {
0127         typedef typename boost::conditional<
0128                 boost::is_float<Source>::value,
0129                 boost::type_identity<Source>,
0130                 boost::make_unsigned<Source>
0131         >::type usource_lazy_t;
0132         typedef typename usource_lazy_t::type usource_t;
0133 
0134         if (arg < 0) {
0135             const bool res = boost::detail::noexcept_numeric_convert<Target, usource_t>(
0136                 static_cast<usource_t>(0u - static_cast<usource_t>(arg)), result
0137             );
0138             result = static_cast<Target>(0u - result);
0139             return res;
0140         } else {
0141             return boost::detail::noexcept_numeric_convert<Target, usource_t>(arg, result);
0142         }
0143     }
0144 };
0145 
0146 /*
0147  * dynamic_num_converter_impl follows the rules:
0148  * 1) If Source can be converted to Target without precision loss and
0149  * without overflows, then assign Source to Target and return
0150  *
0151  * 2) If Source is less than 0 and Target is an unsigned integer,
0152  * then negate Source, check the requirements of rule 1) and if
0153  * successful, assign static_casted Source to Target and return
0154  *
0155  * 3) Otherwise throw a bad_lexical_cast exception
0156  *
0157  *
0158  * Rule 2) required because boost::lexical_cast has the behavior of
0159  * stringstream, which uses the rules of scanf for conversions. And
0160  * in the C99 standard for unsigned input value minus sign is
0161  * optional, so if a negative number is read, no errors will arise
0162  * and the result will be the two's complement.
0163  */
0164 template <typename Target, typename Source>
0165 struct dynamic_num_converter_impl
0166 {
0167     static inline bool try_convert(Source arg, Target& result) noexcept {
0168         typedef typename boost::conditional<
0169             boost::is_unsigned<Target>::value &&
0170             (boost::is_signed<Source>::value || boost::is_float<Source>::value) &&
0171             !(boost::is_same<Source, bool>::value) &&
0172             !(boost::is_same<Target, bool>::value),
0173             lexical_cast_dynamic_num_ignoring_minus,
0174             lexical_cast_dynamic_num_not_ignoring_minus
0175         >::type caster_type;
0176 
0177         return caster_type::try_convert(arg, result);
0178     }
0179 };
0180 
0181 }} // namespace boost::detail
0182 
0183 #endif // BOOST_LEXICAL_CAST_DETAIL_CONVERTER_NUMERIC_HPP
0184