Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-04-19 08:19:40

0001 // Copyright 2023 Matt Borland
0002 // Distributed under the Boost Software License, Version 1.0.
0003 // https://www.boost.org/LICENSE_1_0.txt
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 // Convert characters for 0-9, A-Z, a-z to 0-35. Anything else is 255
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) // unary minus operator applied to unsigned type, result still unsigned
0095 # pragma warning(disable: 4189) // 'is_negative': local variable is initialized but not referenced
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     // Check pre-conditions
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     // Strip sign if the type is signed
0130     // Negative sign will be appended at the end of parsing
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             // Overflow value would cause INT128_MIN in non-base10 to fail
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     // If the only character was a sign abort now
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     // In non-GNU mode on GCC numeric limits may not be specialized
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         // Check that the first character is valid before proceeding
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             // overflow is not possible in the first nd characters
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                 // Required to keep updating the value of next, but the result is garbage
0274                 overflowed = true;
0275             }
0276 
0277             ++next;
0278         }
0279     }
0280 
0281     // Return the parsed value, adding the sign back if applicable
0282     // If we have overflowed then we do not return the result 
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 // Only from_chars for integer types is constexpr (as of C++23)
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 }}} // Namespaces
0332 
0333 #endif // BOOST_CHARCONV_DETAIL_FROM_CHARS_INTEGER_IMPL_HPP