GCC Code Coverage Report


Directory: libs/json/include/boost/json/
File: detail/charconv/detail/from_chars_integer_impl.hpp
Date: 2025-12-23 17:20:53
Exec Total Coverage
Lines: 0 56 0.0%
Functions: 0 3 0.0%
Branches: 0 42 0.0%

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