1// Copyright 2022 Peter Dimov
2// Copyright 2023 Matt Borland
3// Distributed under the Boost Software License, Version 1.0.
4// https://www.boost.org/LICENSE_1_0.txt
5
6// https://stackoverflow.com/questions/38060411/visual-studio-2015-wont-suppress-error-c4996
7#ifndef _SCL_SECURE_NO_WARNINGS
8# define _SCL_SECURE_NO_WARNINGS
9#endif
10#ifndef NO_WARN_MBCS_MFC_DEPRECATION
11# define NO_WARN_MBCS_MFC_DEPRECATION
12#endif
13
14#include "from_chars_float_impl.hpp"
15#include <boost/charconv/detail/fast_float/fast_float.hpp>
16#include <boost/charconv/from_chars.hpp>
17#include <boost/charconv/detail/bit_layouts.hpp>
18#include <boost/charconv/detail/generate_nan.hpp>
19#include <system_error>
20#include <string>
21#include <cstdlib>
22#include <cerrno>
23#include <cstring>
24#include <limits>
25
26#if BOOST_CHARCONV_LDBL_BITS > 64
27# include <boost/charconv/detail/compute_float80.hpp>
28# include <boost/charconv/detail/emulated128.hpp>
29#endif
30
31#if defined(__GNUC__) && __GNUC__ < 5
32# pragma GCC diagnostic ignored "-Wmissing-field-initializers"
33#endif
34
35boost::charconv::from_chars_result boost::charconv::from_chars_erange(const char* first, const char* last, float& value, boost::charconv::chars_format fmt) noexcept
36{
37 if (fmt != boost::charconv::chars_format::hex)
38 {
39 return boost::charconv::detail::fast_float::from_chars(first, last, value, fmt);
40 }
41 return boost::charconv::detail::from_chars_float_impl(first, last, value, fmt);
42}
43
44boost::charconv::from_chars_result boost::charconv::from_chars_erange(const char* first, const char* last, double& value, boost::charconv::chars_format fmt) noexcept
45{
46 if (fmt != boost::charconv::chars_format::hex)
47 {
48 return boost::charconv::detail::fast_float::from_chars(first, last, value, fmt);
49 }
50 return boost::charconv::detail::from_chars_float_impl(first, last, value, fmt);
51}
52
53#ifdef BOOST_CHARCONV_HAS_FLOAT128
54boost::charconv::from_chars_result boost::charconv::from_chars_erange(const char* first, const char* last, __float128& value, boost::charconv::chars_format fmt) noexcept
55{
56 bool sign {};
57 std::int64_t exponent {};
58
59 #if defined(BOOST_CHARCONV_HAS_INT128) && ((defined(__clang_major__) && __clang_major__ > 12 ) || \
60 (defined(BOOST_GCC) && BOOST_GCC > 100000))
61
62 boost::uint128_type significand {};
63
64 #else
65 boost::charconv::detail::uint128 significand {};
66 #endif
67
68 auto r = boost::charconv::detail::parser(first, last, sign, significand, exponent, fmt);
69 if (r.ec == std::errc::value_too_large)
70 {
71 r.ec = std::errc();
72
73 #if BOOST_CHARCONV_HAS_BUILTIN(__builtin_inf)
74 value = sign ? -static_cast<__float128>(__builtin_inf()) : static_cast<__float128>(__builtin_inf());
75 #else // Conversion from HUGE_VALL should work
76 value = sign ? -static_cast<__float128>(HUGE_VALL) : static_cast<__float128>(HUGE_VALL);
77 #endif
78
79 return r;
80 }
81 else if (r.ec == std::errc::not_supported)
82 {
83 r.ec = std::errc();
84 if (significand == 0)
85 {
86 #if BOOST_CHARCONV_HAS_BUILTIN(__builtin_nanq)
87 value = sign ? -static_cast<__float128>(__builtin_nanq("")) : static_cast<__float128>(__builtin_nanq(""));
88 #elif BOOST_CHARCONV_HAS_BUILTIN(__nanq)
89 value = sign ? -static_cast<__float128>(__nanq("")) : static_cast<__float128>(__nanq(""));
90 #else
91 value = boost::charconv::detail::nanq();
92 value = sign ? -value : value;
93 #endif
94 }
95 else
96 {
97 #if BOOST_CHARCONV_HAS_BUILTIN(__builtin_nansq)
98 value = sign ? -static_cast<__float128>(__builtin_nansq("")) : static_cast<__float128>(__builtin_nansq(""));
99 #elif BOOST_CHARCONV_HAS_BUILTIN(__nansq)
100 value = sign ? -static_cast<__float128>(__nansq("")) : static_cast<__float128>(__nansq(""));
101 #else
102 value = boost::charconv::detail::nans();
103 value = sign ? -value : value;
104 #endif
105 }
106
107 return r;
108 }
109 else if (r.ec != std::errc())
110 {
111 return r;
112 }
113 else if (significand == 0)
114 {
115 value = sign ? -0.0Q : 0.0Q;
116 return r;
117 }
118
119 std::errc success {};
120 auto return_val = boost::charconv::detail::compute_float128(exponent, significand, sign, success);
121 r.ec = static_cast<std::errc>(success);
122
123 if (r.ec == std::errc() || r.ec == std::errc::result_out_of_range)
124 {
125 value = return_val;
126 }
127 else if (r.ec == std::errc::not_supported)
128 {
129 // Fallback routine
130 r = boost::charconv::detail::from_chars_strtod(first, last, value);
131 }
132
133 return r;
134}
135#endif
136
137#ifdef BOOST_CHARCONV_HAS_FLOAT16
138boost::charconv::from_chars_result boost::charconv::from_chars_erange(const char* first, const char* last, std::float16_t& value, boost::charconv::chars_format fmt) noexcept
139{
140 float f;
141 const auto r = boost::charconv::from_chars_erange(first, last, f, fmt);
142 if (r.ec == std::errc())
143 {
144 value = static_cast<std::float16_t>(f);
145 }
146 return r;
147}
148#endif
149
150#ifdef BOOST_CHARCONV_HAS_FLOAT32
151boost::charconv::from_chars_result boost::charconv::from_chars_erange(const char* first, const char* last, std::float32_t& value, boost::charconv::chars_format fmt) noexcept
152{
153 static_assert(std::numeric_limits<std::float32_t>::digits == FLT_MANT_DIG &&
154 std::numeric_limits<std::float32_t>::min_exponent == FLT_MIN_EXP,
155 "float and std::float32_t are not the same layout like they should be");
156
157 float f;
158 std::memcpy(&f, &value, sizeof(float));
159 const auto r = boost::charconv::from_chars_erange(first, last, f, fmt);
160 std::memcpy(&value, &f, sizeof(std::float32_t));
161 return r;
162}
163#endif
164
165#ifdef BOOST_CHARCONV_HAS_FLOAT64
166boost::charconv::from_chars_result boost::charconv::from_chars_erange(const char* first, const char* last, std::float64_t& value, boost::charconv::chars_format fmt) noexcept
167{
168 static_assert(std::numeric_limits<std::float64_t>::digits == DBL_MANT_DIG &&
169 std::numeric_limits<std::float64_t>::min_exponent == DBL_MIN_EXP,
170 "double and std::float64_t are not the same layout like they should be");
171
172 double d;
173 std::memcpy(&d, &value, sizeof(double));
174 const auto r = boost::charconv::from_chars_erange(first, last, d, fmt);
175 std::memcpy(&value, &d, sizeof(std::float64_t));
176 return r;
177}
178#endif
179
180#ifdef BOOST_CHARCONV_HAS_BRAINFLOAT16
181boost::charconv::from_chars_result boost::charconv::from_chars_erange(const char* first, const char* last, std::bfloat16_t& value, boost::charconv::chars_format fmt) noexcept
182{
183 float f;
184 const auto r = boost::charconv::from_chars_erange(first, last, f, fmt);
185 if (r.ec == std::errc())
186 {
187 value = static_cast<std::bfloat16_t>(f);
188 }
189 return r;
190}
191#endif
192
193#if BOOST_CHARCONV_LDBL_BITS == 64 || defined(BOOST_MSVC)
194
195// Since long double is just a double we use the double implementation and cast into value
196boost::charconv::from_chars_result boost::charconv::from_chars_erange(const char* first, const char* last, long double& value, boost::charconv::chars_format fmt) noexcept
197{
198 static_assert(sizeof(double) == sizeof(long double), "64 bit long double detected, but the size is incorrect");
199
200 double d;
201 std::memcpy(&d, &value, sizeof(double));
202 const auto r = boost::charconv::from_chars_erange(first, last, d, fmt);
203 std::memcpy(&value, &d, sizeof(long double));
204
205 return r;
206}
207
208#else
209
210boost::charconv::from_chars_result boost::charconv::from_chars_erange(const char* first, const char* last, long double& value, boost::charconv::chars_format fmt) noexcept
211{
212 static_assert(std::numeric_limits<long double>::is_iec559, "Long double must be IEEE 754 compliant");
213
214 bool sign {};
215 std::int64_t exponent {};
216
217 #if defined(BOOST_CHARCONV_HAS_INT128) && ((defined(__clang_major__) && __clang_major__ > 12 ) || \
218 (defined(BOOST_GCC) && BOOST_GCC > 100000))
219
220 boost::uint128_type significand {};
221
222 #else
223 boost::charconv::detail::uint128 significand {};
224 #endif
225
226 auto r = boost::charconv::detail::parser(first, last, sign, significand, exponent, fmt);
227 if (r.ec == std::errc::value_too_large)
228 {
229 r.ec = std::errc();
230 value = sign ? -std::numeric_limits<long double>::infinity() : std::numeric_limits<long double>::infinity();
231 return r;
232 }
233 else if (r.ec == std::errc::not_supported)
234 {
235 r.ec = std::errc();
236 if (significand == 0)
237 {
238 value = sign ? -std::numeric_limits<long double>::quiet_NaN() : std::numeric_limits<long double>::quiet_NaN();
239 }
240 else
241 {
242 value = sign ? -std::numeric_limits<long double>::signaling_NaN() : std::numeric_limits<long double>::signaling_NaN();
243 }
244
245 return r;
246 }
247 else if (r.ec != std::errc())
248 {
249 return r;
250 }
251 else if (significand == 0)
252 {
253 value = sign ? -0.0L : 0.0L;
254 return r;
255 }
256
257 std::errc success {};
258 auto return_val = boost::charconv::detail::compute_float80<long double>(q: exponent, w: significand, negative: sign, success);
259 r.ec = success;
260
261 if (r.ec == std::errc() || r.ec == std::errc::result_out_of_range)
262 {
263 value = return_val;
264 }
265 else if (r.ec == std::errc::not_supported)
266 {
267 // Fallback routine
268 r = boost::charconv::detail::from_chars_strtod(first, last, value);
269 }
270
271 return r;
272}
273
274#if defined(BOOST_CHARCONV_HAS_STDFLOAT128) && defined(BOOST_CHARCONV_HAS_FLOAT128)
275boost::charconv::from_chars_result boost::charconv::from_chars_erange(const char* first, const char* last, std::float128_t& value, boost::charconv::chars_format fmt) noexcept
276{
277 static_assert(sizeof(__float128) == sizeof(std::float128_t));
278
279 __float128 q;
280 std::memcpy(&q, &value, sizeof(__float128));
281 const auto r = boost::charconv::from_chars_erange(first, last, q, fmt);
282 std::memcpy(&value, &q, sizeof(std::float128_t));
283
284 return r;
285}
286#endif
287
288#endif // long double implementations
289
290// String view overloads
291
292boost::charconv::from_chars_result boost::charconv::from_chars_erange(boost::core::string_view sv, float& value, boost::charconv::chars_format fmt) noexcept
293{
294 return boost::charconv::from_chars_erange(first: sv.data(), last: sv.data() + sv.size(), value, fmt);
295}
296
297boost::charconv::from_chars_result boost::charconv::from_chars_erange(boost::core::string_view sv, double & value, boost::charconv::chars_format fmt) noexcept
298{
299 return boost::charconv::from_chars_erange(first: sv.data(), last: sv.data() + sv.size(), value, fmt);
300}
301
302boost::charconv::from_chars_result boost::charconv::from_chars_erange(boost::core::string_view sv, long double& value, boost::charconv::chars_format fmt) noexcept
303{
304 return boost::charconv::from_chars_erange(first: sv.data(), last: sv.data() + sv.size(), value, fmt);
305}
306
307#ifdef BOOST_CHARCONV_HAS_FLOAT128
308boost::charconv::from_chars_result boost::charconv::from_chars_erange(boost::core::string_view sv, __float128& value, boost::charconv::chars_format fmt) noexcept
309{
310 return boost::charconv::from_chars_erange(sv.data(), sv.data() + sv.size(), value, fmt);
311}
312#endif
313
314// <stdfloat> types
315#ifdef BOOST_CHARCONV_HAS_FLOAT16
316boost::charconv::from_chars_result boost::charconv::from_chars_erange(boost::core::string_view sv, std::float16_t& value, boost::charconv::chars_format fmt) noexcept
317{
318 return boost::charconv::from_chars_erange(sv.data(), sv.data() + sv.size(), value, fmt);
319}
320#endif
321#ifdef BOOST_CHARCONV_HAS_FLOAT32
322boost::charconv::from_chars_result boost::charconv::from_chars_erange(boost::core::string_view sv, std::float32_t& value, boost::charconv::chars_format fmt) noexcept
323{
324 return boost::charconv::from_chars_erange(sv.data(), sv.data() + sv.size(), value, fmt);
325}
326#endif
327#ifdef BOOST_CHARCONV_HAS_FLOAT64
328boost::charconv::from_chars_result boost::charconv::from_chars_erange(boost::core::string_view sv, std::float64_t& value, boost::charconv::chars_format fmt) noexcept
329{
330 return boost::charconv::from_chars_erange(sv.data(), sv.data() + sv.size(), value, fmt);
331}
332#endif
333#if defined(BOOST_CHARCONV_HAS_STDFLOAT128) && defined(BOOST_CHARCONV_HAS_FLOAT128)
334boost::charconv::from_chars_result boost::charconv::from_chars_erange(boost::core::string_view sv, std::float128_t& value, boost::charconv::chars_format fmt) noexcept
335{
336 return boost::charconv::from_chars_erange(sv.data(), sv.data() + sv.size(), value, fmt);
337}
338#endif
339#ifdef BOOST_CHARCONV_HAS_BRAINFLOAT16
340boost::charconv::from_chars_result boost::charconv::from_chars_erange(boost::core::string_view sv, std::bfloat16_t& value, boost::charconv::chars_format fmt) noexcept
341{
342 return boost::charconv::from_chars_erange(sv.data(), sv.data() + sv.size(), value, fmt);
343}
344#endif
345
346namespace {
347
348// Adheres to the STL strictly as opposed to fixing the ERANGE problem (which pre-review was the library default behavior)
349template <typename T>
350boost::charconv::from_chars_result from_chars_strict_impl(const char *first, const char *last, T &value, boost::charconv::chars_format fmt) noexcept
351{
352 T temp_value;
353 const auto r = boost::charconv::from_chars_erange(first, last, temp_value, fmt);
354
355 if (r)
356 {
357 value = temp_value;
358 }
359
360 return r;
361}
362
363}
364
365boost::charconv::from_chars_result boost::charconv::from_chars(const char* first, const char* last, float& value, boost::charconv::chars_format fmt) noexcept
366{
367 return from_chars_strict_impl(first, last, value, fmt);
368}
369
370boost::charconv::from_chars_result boost::charconv::from_chars(const char* first, const char* last, double& value, boost::charconv::chars_format fmt) noexcept
371{
372 return from_chars_strict_impl(first, last, value, fmt);
373}
374
375boost::charconv::from_chars_result boost::charconv::from_chars(const char* first, const char* last, long double& value, boost::charconv::chars_format fmt) noexcept
376{
377 return from_chars_strict_impl(first, last, value, fmt);
378}
379
380#ifdef BOOST_CHARCONV_HAS_FLOAT128
381boost::charconv::from_chars_result boost::charconv::from_chars(const char* first, const char* last, __float128& value, boost::charconv::chars_format fmt) noexcept
382{
383 return from_chars_strict_impl(first, last, value, fmt);
384}
385#endif
386
387#ifdef BOOST_CHARCONV_HAS_FLOAT16
388boost::charconv::from_chars_result boost::charconv::from_chars(const char* first, const char* last, std::float16_t& value, boost::charconv::chars_format fmt) noexcept
389{
390 return from_chars_strict_impl(first, last, value, fmt);
391}
392#endif
393
394#ifdef BOOST_CHARCONV_HAS_FLOAT32
395boost::charconv::from_chars_result boost::charconv::from_chars(const char* first, const char* last, std::float32_t& value, boost::charconv::chars_format fmt) noexcept
396{
397 return from_chars_strict_impl(first, last, value, fmt);
398}
399#endif
400
401#ifdef BOOST_CHARCONV_HAS_FLOAT64
402boost::charconv::from_chars_result boost::charconv::from_chars(const char* first, const char* last, std::float64_t& value, boost::charconv::chars_format fmt) noexcept
403{
404 return from_chars_strict_impl(first, last, value, fmt);
405}
406#endif
407
408#if defined(BOOST_CHARCONV_HAS_STDFLOAT128) && defined(BOOST_CHARCONV_HAS_FLOAT128)
409boost::charconv::from_chars_result boost::charconv::from_chars(const char* first, const char* last, std::float128_t& value, boost::charconv::chars_format fmt) noexcept
410{
411 return from_chars_strict_impl(first, last, value, fmt);
412}
413#endif
414
415#ifdef BOOST_CHARCONV_HAS_BRAINFLOAT16
416boost::charconv::from_chars_result boost::charconv::from_chars(const char* first, const char* last, std::bfloat16_t& value, boost::charconv::chars_format fmt) noexcept
417{
418 return from_chars_strict_impl(first, last, value, fmt);
419}
420#endif
421
422boost::charconv::from_chars_result boost::charconv::from_chars(boost::core::string_view sv, float& value, boost::charconv::chars_format fmt) noexcept
423{
424 return from_chars_strict_impl(first: sv.data(), last: sv.data() + sv.size(), value, fmt);
425}
426
427boost::charconv::from_chars_result boost::charconv::from_chars(boost::core::string_view sv, double& value, boost::charconv::chars_format fmt) noexcept
428{
429 return from_chars_strict_impl(first: sv.data(), last: sv.data() + sv.size(), value, fmt);
430}
431
432boost::charconv::from_chars_result boost::charconv::from_chars(boost::core::string_view sv, long double& value, boost::charconv::chars_format fmt) noexcept
433{
434 return from_chars_strict_impl(first: sv.data(), last: sv.data() + sv.size(), value, fmt);
435}
436
437#ifdef BOOST_CHARCONV_HAS_FLOAT128
438boost::charconv::from_chars_result boost::charconv::from_chars(boost::core::string_view sv, __float128& value, boost::charconv::chars_format fmt) noexcept
439{
440 return from_chars_strict_impl(sv.data(), sv.data() + sv.size(), value, fmt);
441}
442#endif
443
444#ifdef BOOST_CHARCONV_HAS_FLOAT16
445boost::charconv::from_chars_result boost::charconv::from_chars(boost::core::string_view sv, std::float16_t& value, boost::charconv::chars_format fmt) noexcept
446{
447 return from_chars_strict_impl(sv.data(), sv.data() + sv.size(), value, fmt);
448}
449#endif
450
451#ifdef BOOST_CHARCONV_HAS_FLOAT32
452boost::charconv::from_chars_result boost::charconv::from_chars(boost::core::string_view sv, std::float32_t& value, boost::charconv::chars_format fmt) noexcept
453{
454 return from_chars_strict_impl(sv.data(), sv.data() + sv.size(), value, fmt);
455}
456#endif
457
458#ifdef BOOST_CHARCONV_HAS_FLOAT64
459boost::charconv::from_chars_result boost::charconv::from_chars(boost::core::string_view sv, std::float64_t& value, boost::charconv::chars_format fmt) noexcept
460{
461 return from_chars_strict_impl(sv.data(), sv.data() + sv.size(), value, fmt);
462}
463#endif
464
465#if defined(BOOST_CHARCONV_HAS_STDFLOAT128) && defined(BOOST_CHARCONV_HAS_FLOAT128)
466boost::charconv::from_chars_result boost::charconv::from_chars(boost::core::string_view sv, std::float128_t& value, boost::charconv::chars_format fmt) noexcept
467{
468 return from_chars_strict_impl(sv.data(), sv.data() + sv.size(), value, fmt);
469}
470#endif
471
472#ifdef BOOST_CHARCONV_HAS_BRAINFLOAT16
473boost::charconv::from_chars_result boost::charconv::from_chars(boost::core::string_view sv, std::bfloat16_t& value, boost::charconv::chars_format fmt) noexcept
474{
475 return from_chars_strict_impl(sv.data(), sv.data() + sv.size(), value, fmt);
476}
477#endif
478

source code of boost/libs/charconv/src/from_chars.cpp