0.00% Lines (0/56) 0.00% Functions (0/3)
TLA Baseline Branch
Line Hits Code Line Hits Code
1   // Copyright 2023 Matt Borland 1   // Copyright 2023 Matt Borland
2   // Distributed under the Boost Software License, Version 1.0. 2   // Distributed under the Boost Software License, Version 1.0.
3   // https://www.boost.org/LICENSE_1_0.txt 3   // https://www.boost.org/LICENSE_1_0.txt
4   4  
5   #ifndef BOOST_JSON_DETAIL_CHARCONV_DETAIL_FROM_CHARS_INTEGER_IMPL_HPP 5   #ifndef BOOST_JSON_DETAIL_CHARCONV_DETAIL_FROM_CHARS_INTEGER_IMPL_HPP
6   #define BOOST_JSON_DETAIL_CHARCONV_DETAIL_FROM_CHARS_INTEGER_IMPL_HPP 6   #define BOOST_JSON_DETAIL_CHARCONV_DETAIL_FROM_CHARS_INTEGER_IMPL_HPP
7   7  
8   #include <boost/json/detail/charconv/detail/config.hpp> 8   #include <boost/json/detail/charconv/detail/config.hpp>
9   #include <boost/json/detail/charconv/detail/from_chars_result.hpp> 9   #include <boost/json/detail/charconv/detail/from_chars_result.hpp>
10   #include <boost/config.hpp> 10   #include <boost/config.hpp>
11   #include <system_error> 11   #include <system_error>
12   #include <type_traits> 12   #include <type_traits>
13   #include <limits> 13   #include <limits>
14   #include <cstdlib> 14   #include <cstdlib>
15   #include <cerrno> 15   #include <cerrno>
16   #include <cstddef> 16   #include <cstddef>
17   #include <cstdint> 17   #include <cstdint>
18   18  
19   namespace boost { namespace json { namespace detail { namespace charconv { namespace detail { 19   namespace boost { namespace json { namespace detail { namespace charconv { namespace detail {
20   20  
21   static constexpr unsigned char uchar_values[] = 21   static constexpr unsigned char uchar_values[] =
22   {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 22   {255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
23   255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 23   255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
24   255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 24   255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
25   0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 255, 255, 255, 255, 255, 255, 25   0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 255, 255, 255, 255, 255, 255,
26   255, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 26   255, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
27   25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 255, 255, 255, 255, 255, 27   25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 255, 255, 255, 255, 255,
28   255, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 28   255, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
29   25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 255, 255, 255, 255, 255, 29   25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 255, 255, 255, 255, 255,
30   255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 30   255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
31   255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 31   255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
32   255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 32   255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
33   255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 33   255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
34   255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 34   255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
35   255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 35   255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
36   255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 36   255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
37   255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255}; 37   255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255};
38   38  
39   static_assert(sizeof(uchar_values) == 256, "uchar_values should represent all 256 values of unsigned char"); 39   static_assert(sizeof(uchar_values) == 256, "uchar_values should represent all 256 values of unsigned char");
40   40  
41   // Convert characters for 0-9, A-Z, a-z to 0-35. Anything else is 255 41   // Convert characters for 0-9, A-Z, a-z to 0-35. Anything else is 255
MISUBC 42   constexpr unsigned char digit_from_char(char val) noexcept 42   constexpr unsigned char digit_from_char(char val) noexcept
43   { 43   {
MISUBC 44   return uchar_values[static_cast<unsigned char>(val)]; 44   return uchar_values[static_cast<unsigned char>(val)];
45   } 45   }
46   46  
47   #ifdef BOOST_MSVC 47   #ifdef BOOST_MSVC
48   # pragma warning(push) 48   # pragma warning(push)
49   # pragma warning(disable: 4146) // unary minus operator applied to unsigned type, result still unsigned 49   # pragma warning(disable: 4146) // unary minus operator applied to unsigned type, result still unsigned
50   # pragma warning(disable: 4189) // 'is_negative': local variable is initialized but not referenced 50   # pragma warning(disable: 4189) // 'is_negative': local variable is initialized but not referenced
51   51  
52   #elif defined(__clang__) 52   #elif defined(__clang__)
53   # pragma clang diagnostic push 53   # pragma clang diagnostic push
54   # pragma clang diagnostic ignored "-Wconstant-conversion" 54   # pragma clang diagnostic ignored "-Wconstant-conversion"
55   55  
56   #elif defined(__GNUC__) && (__GNUC__ < 7) 56   #elif defined(__GNUC__) && (__GNUC__ < 7)
57   # pragma GCC diagnostic push 57   # pragma GCC diagnostic push
58   # pragma GCC diagnostic ignored "-Woverflow" 58   # pragma GCC diagnostic ignored "-Woverflow"
59   59  
60   #elif defined(__GNUC__) && (__GNUC__ >= 7) 60   #elif defined(__GNUC__) && (__GNUC__ >= 7)
61   # pragma GCC diagnostic push 61   # pragma GCC diagnostic push
62   # pragma GCC diagnostic ignored "-Wmaybe-uninitialized" 62   # pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
63   63  
64   #endif 64   #endif
65   65  
66   template <typename Integer, typename Unsigned_Integer> 66   template <typename Integer, typename Unsigned_Integer>
MISUBC 67   BOOST_CXX14_CONSTEXPR from_chars_result from_chars_integer_impl(const char* first, const char* last, Integer& value, int base) noexcept 67   BOOST_CXX14_CONSTEXPR from_chars_result from_chars_integer_impl(const char* first, const char* last, Integer& value, int base) noexcept
68   { 68   {
MISUBC 69   Unsigned_Integer result = 0; 69   Unsigned_Integer result = 0;
MISUBC 70   Unsigned_Integer overflow_value = 0; 70   Unsigned_Integer overflow_value = 0;
MISUBC 71   Unsigned_Integer max_digit = 0; 71   Unsigned_Integer max_digit = 0;
72   72  
73   // Check pre-conditions 73   // Check pre-conditions
MISUBC 74   if (!((first <= last) && (base >= 2 && base <= 36))) 74   if (!((first <= last) && (base >= 2 && base <= 36)))
75   { 75   {
MISUBC 76   return {first, std::errc::invalid_argument}; 76   return {first, std::errc::invalid_argument};
77   } 77   }
78   78  
MISUBC 79   Unsigned_Integer unsigned_base = static_cast<Unsigned_Integer>(base); 79   Unsigned_Integer unsigned_base = static_cast<Unsigned_Integer>(base);
80   80  
81   // Strip sign if the type is signed 81   // Strip sign if the type is signed
82   // Negative sign will be appended at the end of parsing 82   // Negative sign will be appended at the end of parsing
MISUBC 83   BOOST_ATTRIBUTE_UNUSED bool is_negative = false; 83   BOOST_ATTRIBUTE_UNUSED bool is_negative = false;
MISUBC 84   auto next = first; 84   auto next = first;
85   85  
86   #ifdef BOOST_HAS_INT128 86   #ifdef BOOST_HAS_INT128
87   BOOST_IF_CONSTEXPR (std::is_same<Integer, boost::int128_type>::value || std::is_signed<Integer>::value) 87   BOOST_IF_CONSTEXPR (std::is_same<Integer, boost::int128_type>::value || std::is_signed<Integer>::value)
88   #else 88   #else
89   BOOST_IF_CONSTEXPR (std::is_signed<Integer>::value) 89   BOOST_IF_CONSTEXPR (std::is_signed<Integer>::value)
90   #endif 90   #endif
91   { 91   {
MISUBC 92   if (next != last) 92   if (next != last)
93   { 93   {
MISUBC 94   if (*next == '-') 94   if (*next == '-')
95   { 95   {
MISUBC 96   is_negative = true; 96   is_negative = true;
MISUBC 97   ++next; 97   ++next;
98   } 98   }
MISUBC 99   else if (*next == '+') 99   else if (*next == '+')
100   { 100   {
MISUBC 101   return {next, std::errc::invalid_argument}; 101   return {next, std::errc::invalid_argument};
102   } 102   }
103   } 103   }
104   104  
105   #ifdef BOOST_HAS_INT128 105   #ifdef BOOST_HAS_INT128
106   BOOST_IF_CONSTEXPR (std::is_same<Integer, boost::int128_type>::value) 106   BOOST_IF_CONSTEXPR (std::is_same<Integer, boost::int128_type>::value)
107   { 107   {
108   overflow_value = BOOST_JSON_INT128_MAX; 108   overflow_value = BOOST_JSON_INT128_MAX;
109   max_digit = BOOST_JSON_INT128_MAX; 109   max_digit = BOOST_JSON_INT128_MAX;
110   } 110   }
111   else 111   else
112   #endif 112   #endif
113   { 113   {
MISUBC 114   overflow_value = (std::numeric_limits<Integer>::max)(); 114   overflow_value = (std::numeric_limits<Integer>::max)();
MISUBC 115   max_digit = (std::numeric_limits<Integer>::max)(); 115   max_digit = (std::numeric_limits<Integer>::max)();
116   } 116   }
117   117  
MISUBC 118   if (is_negative) 118   if (is_negative)
119   { 119   {
MISUBC 120   ++overflow_value; 120   ++overflow_value;
MISUBC 121   ++max_digit; 121   ++max_digit;
122   } 122   }
123   } 123   }
124   else 124   else
125   { 125   {
MISUBC 126   if (next != last && (*next == '-' || *next == '+')) 126   if (next != last && (*next == '-' || *next == '+'))
127   { 127   {
MISUBC 128   return {first, std::errc::invalid_argument}; 128   return {first, std::errc::invalid_argument};
129   } 129   }
130   130  
131   #ifdef BOOST_HAS_INT128 131   #ifdef BOOST_HAS_INT128
132   BOOST_IF_CONSTEXPR (std::is_same<Integer, boost::uint128_type>::value) 132   BOOST_IF_CONSTEXPR (std::is_same<Integer, boost::uint128_type>::value)
133   { 133   {
134   overflow_value = BOOST_JSON_UINT128_MAX; 134   overflow_value = BOOST_JSON_UINT128_MAX;
135   max_digit = BOOST_JSON_UINT128_MAX; 135   max_digit = BOOST_JSON_UINT128_MAX;
136   } 136   }
137   else 137   else
138   #endif 138   #endif
139   { 139   {
MISUBC 140   overflow_value = (std::numeric_limits<Unsigned_Integer>::max)(); 140   overflow_value = (std::numeric_limits<Unsigned_Integer>::max)();
MISUBC 141   max_digit = (std::numeric_limits<Unsigned_Integer>::max)(); 141   max_digit = (std::numeric_limits<Unsigned_Integer>::max)();
142   } 142   }
143   } 143   }
144   144  
145   #ifdef BOOST_HAS_INT128 145   #ifdef BOOST_HAS_INT128
146   BOOST_IF_CONSTEXPR (std::is_same<Integer, boost::int128_type>::value) 146   BOOST_IF_CONSTEXPR (std::is_same<Integer, boost::int128_type>::value)
147   { 147   {
148   overflow_value /= unsigned_base; 148   overflow_value /= unsigned_base;
149   max_digit %= unsigned_base; 149   max_digit %= unsigned_base;
150   overflow_value *= 2; // Overflow value would cause INT128_MIN in non-base10 to fail 150   overflow_value *= 2; // Overflow value would cause INT128_MIN in non-base10 to fail
151   } 151   }
152   else 152   else
153   #endif 153   #endif
154   { 154   {
MISUBC 155   overflow_value /= unsigned_base; 155   overflow_value /= unsigned_base;
MISUBC 156   max_digit %= unsigned_base; 156   max_digit %= unsigned_base;
157   } 157   }
158   158  
159   // If the only character was a sign abort now 159   // If the only character was a sign abort now
MISUBC 160   if (next == last) 160   if (next == last)
161   { 161   {
MISUBC 162   return {first, std::errc::invalid_argument}; 162   return {first, std::errc::invalid_argument};
163   } 163   }
164   164  
MISUBC 165   bool overflowed = false; 165   bool overflowed = false;
166   166  
MISUBC 167   std::ptrdiff_t nc = last - next; 167   std::ptrdiff_t nc = last - next;
MISUBC 168   constexpr std::ptrdiff_t nd = std::numeric_limits<Integer>::digits10; 168   constexpr std::ptrdiff_t nd = std::numeric_limits<Integer>::digits10;
169   169  
170   { 170   {
MISUBC 171   std::ptrdiff_t i = 0; 171   std::ptrdiff_t i = 0;
172   172  
MISUBC 173   for( ; i < nd && i < nc; ++i ) 173   for( ; i < nd && i < nc; ++i )
174   { 174   {
175   // overflow is not possible in the first nd characters 175   // overflow is not possible in the first nd characters
176   176  
MISUBC 177   const unsigned char current_digit = digit_from_char(*next); 177   const unsigned char current_digit = digit_from_char(*next);
178   178  
MISUBC 179   if (current_digit >= unsigned_base) 179   if (current_digit >= unsigned_base)
180   { 180   {
MISUBC 181   break; 181   break;
182   } 182   }
183   183  
MISUBC 184   result = static_cast<Unsigned_Integer>(result * unsigned_base + current_digit); 184   result = static_cast<Unsigned_Integer>(result * unsigned_base + current_digit);
MISUBC 185   ++next; 185   ++next;
186   } 186   }
187   187  
MISUBC 188   for( ; i < nc; ++i ) 188   for( ; i < nc; ++i )
189   { 189   {
MISUBC 190   const unsigned char current_digit = digit_from_char(*next); 190   const unsigned char current_digit = digit_from_char(*next);
191   191  
MISUBC 192   if (current_digit >= unsigned_base) 192   if (current_digit >= unsigned_base)
193   { 193   {
MISUBC 194   break; 194   break;
195   } 195   }
196   196  
MISUBC 197   if (result < overflow_value || (result == overflow_value && current_digit <= max_digit)) 197   if (result < overflow_value || (result == overflow_value && current_digit <= max_digit))
198   { 198   {
MISUBC 199   result = static_cast<Unsigned_Integer>(result * unsigned_base + current_digit); 199   result = static_cast<Unsigned_Integer>(result * unsigned_base + current_digit);
200   } 200   }
201   else 201   else
202   { 202   {
203   // Required to keep updating the value of next, but the result is garbage 203   // Required to keep updating the value of next, but the result is garbage
MISUBC 204   overflowed = true; 204   overflowed = true;
205   } 205   }
206   206  
MISUBC 207   ++next; 207   ++next;
208   } 208   }
209   } 209   }
210   210  
211   // Return the parsed value, adding the sign back if applicable 211   // Return the parsed value, adding the sign back if applicable
212   // If we have overflowed then we do not return the result 212   // If we have overflowed then we do not return the result
MISUBC 213   if (overflowed) 213   if (overflowed)
214   { 214   {
MISUBC 215   return {next, std::errc::result_out_of_range}; 215   return {next, std::errc::result_out_of_range};
216   } 216   }
217   217  
MISUBC 218   value = static_cast<Integer>(result); 218   value = static_cast<Integer>(result);
219   #ifdef BOOST_HAS_INT128 219   #ifdef BOOST_HAS_INT128
220   BOOST_IF_CONSTEXPR (std::is_same<Integer, boost::int128_type>::value || std::is_signed<Integer>::value) 220   BOOST_IF_CONSTEXPR (std::is_same<Integer, boost::int128_type>::value || std::is_signed<Integer>::value)
221   #else 221   #else
222   BOOST_IF_CONSTEXPR (std::is_signed<Integer>::value) 222   BOOST_IF_CONSTEXPR (std::is_signed<Integer>::value)
223   #endif 223   #endif
224   { 224   {
MISUBC 225   if (is_negative) 225   if (is_negative)
226   { 226   {
MISUBC 227   value = -(static_cast<Unsigned_Integer>(value)); 227   value = -(static_cast<Unsigned_Integer>(value));
228   } 228   }
229   } 229   }
230   230  
MISUBC 231   return {next, std::errc()}; 231   return {next, std::errc()};
232   } 232   }
233   233  
234   #ifdef BOOST_MSVC 234   #ifdef BOOST_MSVC
235   # pragma warning(pop) 235   # pragma warning(pop)
236   #elif defined(__clang__) && defined(__APPLE__) 236   #elif defined(__clang__) && defined(__APPLE__)
237   # pragma clang diagnostic pop 237   # pragma clang diagnostic pop
238   #elif defined(__GNUC__) && (__GNUC__ < 7 || __GNUC__ >= 9) 238   #elif defined(__GNUC__) && (__GNUC__ < 7 || __GNUC__ >= 9)
239   # pragma GCC diagnostic pop 239   # pragma GCC diagnostic pop
240   #endif 240   #endif
241   241  
242   // Only from_chars for integer types is constexpr (as of C++23) 242   // Only from_chars for integer types is constexpr (as of C++23)
243   template <typename Integer> 243   template <typename Integer>
MISUBC 244   BOOST_JSON_GCC5_CONSTEXPR from_chars_result from_chars(const char* first, const char* last, Integer& value, int base = 10) noexcept 244   BOOST_JSON_GCC5_CONSTEXPR from_chars_result from_chars(const char* first, const char* last, Integer& value, int base = 10) noexcept
245   { 245   {
246   using Unsigned_Integer = typename std::make_unsigned<Integer>::type; 246   using Unsigned_Integer = typename std::make_unsigned<Integer>::type;
MISUBC 247   return detail::from_chars_integer_impl<Integer, Unsigned_Integer>(first, last, value, base); 247   return detail::from_chars_integer_impl<Integer, Unsigned_Integer>(first, last, value, base);
248   } 248   }
249   249  
250   }}}}} // Namespaces 250   }}}}} // Namespaces
251   251  
252   #endif // BOOST_JSON_DETAIL_CHARCONV_DETAIL_FROM_CHARS_INTEGER_IMPL_HPP 252   #endif // BOOST_JSON_DETAIL_CHARCONV_DETAIL_FROM_CHARS_INTEGER_IMPL_HPP