File indexing completed on 2025-07-06 08:17:56
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
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
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
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
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
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
0148
0149
0150
0151
0152
0153
0154
0155
0156
0157
0158
0159
0160
0161
0162
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 }}
0182
0183 #endif
0184