File indexing completed on 2025-04-19 08:19:40
0001
0002
0003
0004
0005 #ifndef BOOST_CHARCONV_DETAIL_FROM_CHARS_INTEGER_IMPL_HPP
0006 #define BOOST_CHARCONV_DETAIL_FROM_CHARS_INTEGER_IMPL_HPP
0007
0008 #include <boost/charconv/detail/apply_sign.hpp>
0009 #include <boost/charconv/detail/config.hpp>
0010 #include <boost/charconv/detail/from_chars_result.hpp>
0011 #include <boost/charconv/detail/emulated128.hpp>
0012 #include <boost/charconv/detail/type_traits.hpp>
0013 #include <boost/charconv/config.hpp>
0014 #include <boost/config.hpp>
0015 #include <system_error>
0016 #include <type_traits>
0017 #include <limits>
0018 #include <cstdlib>
0019 #include <cerrno>
0020 #include <cstddef>
0021 #include <cstdint>
0022
0023 namespace boost { namespace charconv { namespace detail {
0024
0025 static constexpr unsigned char uchar_values[] =
0026 {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
0027 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
0028 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
0029 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 255, 255, 255, 255, 255, 255,
0030 255, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
0031 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 255, 255, 255, 255, 255,
0032 255, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
0033 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 255, 255, 255, 255, 255,
0034 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
0035 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
0036 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
0037 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
0038 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
0039 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
0040 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
0041 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255};
0042
0043 static_assert(sizeof(uchar_values) == 256, "uchar_values should represent all 256 values of unsigned char");
0044
0045 static constexpr double log_2_table[] =
0046 {
0047 0.0,
0048 0.0,
0049 1.0,
0050 0.630929753571,
0051 0.5,
0052 0.430676558073,
0053 0.386852807235,
0054 0.356207187108,
0055 0.333333333333,
0056 0.315464876786,
0057 0.301029995664,
0058 0.289064826318,
0059 0.278942945651,
0060 0.270238154427,
0061 0.262649535037,
0062 0.255958024810,
0063 0.25,
0064 0.244650542118,
0065 0.239812466568,
0066 0.235408913367,
0067 0.231378213160,
0068 0.227670248697,
0069 0.224243824218,
0070 0.221064729458,
0071 0.218104291986,
0072 0.215338279037,
0073 0.212746053553,
0074 0.210309917857,
0075 0.208014597677,
0076 0.205846832460,
0077 0.203795047091,
0078 0.201849086582,
0079 0.2,
0080 0.198239863171,
0081 0.196561632233,
0082 0.194959021894,
0083 0.193426403617
0084 };
0085
0086
0087 constexpr unsigned char digit_from_char(char val) noexcept
0088 {
0089 return uchar_values[static_cast<unsigned char>(val)];
0090 }
0091
0092 #ifdef BOOST_MSVC
0093 # pragma warning(push)
0094 # pragma warning(disable: 4146)
0095 # pragma warning(disable: 4189)
0096
0097 #elif defined(__clang__)
0098 # pragma clang diagnostic push
0099 # pragma clang diagnostic ignored "-Wconstant-conversion"
0100
0101 #elif defined(__GNUC__) && (__GNUC__ < 7)
0102 # pragma GCC diagnostic push
0103 # pragma GCC diagnostic ignored "-Woverflow"
0104 # pragma GCC diagnostic ignored "-Wconversion"
0105 # pragma GCC diagnostic ignored "-Wsign-conversion"
0106
0107 #elif defined(__GNUC__) && (__GNUC__ >= 7)
0108 # pragma GCC diagnostic push
0109 # pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
0110 # pragma GCC diagnostic ignored "-Wconversion"
0111
0112 #endif
0113
0114 template <typename Integer, typename Unsigned_Integer>
0115 BOOST_CXX14_CONSTEXPR from_chars_result from_chars_integer_impl(const char* first, const char* last, Integer& value, int base) noexcept
0116 {
0117 Unsigned_Integer result = 0;
0118 Unsigned_Integer overflow_value = 0;
0119 Unsigned_Integer max_digit = 0;
0120
0121
0122 if (!((first <= last) && (base >= 2 && base <= 36)))
0123 {
0124 return {first, std::errc::invalid_argument};
0125 }
0126
0127 const auto unsigned_base = static_cast<Unsigned_Integer>(base);
0128
0129
0130
0131 BOOST_ATTRIBUTE_UNUSED bool is_negative = false;
0132 auto next = first;
0133
0134 BOOST_CHARCONV_IF_CONSTEXPR (is_signed<Integer>::value)
0135 {
0136 if (next != last)
0137 {
0138 if (*next == '-')
0139 {
0140 is_negative = true;
0141 ++next;
0142 }
0143 else if (*next == '+' || *next == ' ')
0144 {
0145 return {next, std::errc::invalid_argument};
0146 }
0147 }
0148
0149 #ifdef BOOST_CHARCONV_HAS_INT128
0150 BOOST_IF_CONSTEXPR (std::is_same<Integer, boost::int128_type>::value)
0151 {
0152 overflow_value = BOOST_CHARCONV_INT128_MAX;
0153 max_digit = BOOST_CHARCONV_INT128_MAX;
0154 }
0155 else
0156 #endif
0157 {
0158 overflow_value = (std::numeric_limits<Integer>::max)();
0159 max_digit = (std::numeric_limits<Integer>::max)();
0160 }
0161
0162 if (is_negative)
0163 {
0164 ++overflow_value;
0165 ++max_digit;
0166 }
0167 }
0168 else
0169 {
0170 if (next != last && (*next == '-' || *next == '+' || *next == ' '))
0171 {
0172 return {first, std::errc::invalid_argument};
0173 }
0174
0175 #ifdef BOOST_CHARCONV_HAS_INT128
0176 BOOST_IF_CONSTEXPR (std::is_same<Integer, boost::uint128_type>::value)
0177 {
0178 overflow_value = BOOST_CHARCONV_UINT128_MAX;
0179 max_digit = BOOST_CHARCONV_UINT128_MAX;
0180 }
0181 else
0182 #endif
0183 {
0184 overflow_value = (std::numeric_limits<Unsigned_Integer>::max)();
0185 max_digit = (std::numeric_limits<Unsigned_Integer>::max)();
0186 }
0187 }
0188
0189 #ifdef BOOST_CHARCONV_HAS_INT128
0190 BOOST_IF_CONSTEXPR (std::is_same<Integer, boost::int128_type>::value)
0191 {
0192 overflow_value /= unsigned_base;
0193 max_digit %= unsigned_base;
0194 #ifndef __GLIBCXX_TYPE_INT_N_0
0195 if (base != 10)
0196 {
0197
0198 overflow_value *= static_cast<Unsigned_Integer>(2);
0199 }
0200 #endif
0201 }
0202 else
0203 #endif
0204 {
0205 overflow_value /= unsigned_base;
0206 max_digit %= unsigned_base;
0207 }
0208
0209
0210 if (next == last)
0211 {
0212 return {first, std::errc::invalid_argument};
0213 }
0214
0215 bool overflowed = false;
0216
0217 const std::ptrdiff_t nc = last - next;
0218
0219
0220 #if defined(BOOST_CHARCONV_HAS_INT128) && !defined(__GLIBCXX_TYPE_INT_N_0)
0221 constexpr std::ptrdiff_t nd_2 = std::is_same<Integer, boost::int128_type>::value ? 127 :
0222 std::is_same<Integer, boost::uint128_type>::value ? 128 :
0223 std::numeric_limits<Integer>::digits10;
0224 #else
0225 constexpr std::ptrdiff_t nd_2 = std::numeric_limits<Integer>::digits;
0226 #endif
0227
0228 const auto nd = static_cast<std::ptrdiff_t>(nd_2 * log_2_table[static_cast<std::size_t>(unsigned_base)]);
0229
0230 {
0231
0232 const unsigned char first_digit = digit_from_char(*next);
0233
0234 if (first_digit >= unsigned_base)
0235 {
0236 return {first, std::errc::invalid_argument};
0237 }
0238
0239 result = static_cast<Unsigned_Integer>(result * unsigned_base + first_digit);
0240 ++next;
0241 std::ptrdiff_t i = 1;
0242
0243 for( ; i < nd && i < nc; ++i )
0244 {
0245
0246
0247 const unsigned char current_digit = digit_from_char(*next);
0248
0249 if (current_digit >= unsigned_base)
0250 {
0251 break;
0252 }
0253
0254 result = static_cast<Unsigned_Integer>(result * unsigned_base + current_digit);
0255 ++next;
0256 }
0257
0258 for( ; i < nc; ++i )
0259 {
0260 const unsigned char current_digit = digit_from_char(*next);
0261
0262 if (current_digit >= unsigned_base)
0263 {
0264 break;
0265 }
0266
0267 if (result < overflow_value || (result == overflow_value && current_digit <= max_digit))
0268 {
0269 result = static_cast<Unsigned_Integer>(result * unsigned_base + current_digit);
0270 }
0271 else
0272 {
0273
0274 overflowed = true;
0275 }
0276
0277 ++next;
0278 }
0279 }
0280
0281
0282
0283 if (overflowed)
0284 {
0285 return {next, std::errc::result_out_of_range};
0286 }
0287
0288 value = static_cast<Integer>(result);
0289
0290 BOOST_IF_CONSTEXPR (is_signed<Integer>::value)
0291 {
0292 if (is_negative)
0293 {
0294 value = static_cast<Integer>(-(static_cast<Unsigned_Integer>(value)));
0295 }
0296 }
0297
0298 return {next, std::errc()};
0299 }
0300
0301 #ifdef BOOST_MSVC
0302 # pragma warning(pop)
0303 #elif defined(__clang__)
0304 # pragma clang diagnostic pop
0305 #elif defined(__GNUC__)
0306 # pragma GCC diagnostic pop
0307 #endif
0308
0309
0310 template <typename Integer>
0311 BOOST_CHARCONV_GCC5_CONSTEXPR from_chars_result from_chars(const char* first, const char* last, Integer& value, int base = 10) noexcept
0312 {
0313 using Unsigned_Integer = typename std::make_unsigned<Integer>::type;
0314 return detail::from_chars_integer_impl<Integer, Unsigned_Integer>(first, last, value, base);
0315 }
0316
0317 #ifdef BOOST_CHARCONV_HAS_INT128
0318 template <typename Integer>
0319 BOOST_CHARCONV_GCC5_CONSTEXPR from_chars_result from_chars128(const char* first, const char* last, Integer& value, int base = 10) noexcept
0320 {
0321 using Unsigned_Integer = boost::uint128_type;
0322 return detail::from_chars_integer_impl<Integer, Unsigned_Integer>(first, last, value, base);
0323 }
0324 #endif
0325
0326 BOOST_CHARCONV_GCC5_CONSTEXPR from_chars_result from_chars128(const char* first, const char* last, uint128& value, int base = 10) noexcept
0327 {
0328 return from_chars_integer_impl<uint128, uint128>(first, last, value, base);
0329 }
0330
0331 }}}
0332
0333 #endif