GCC Code Coverage Report


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

Line Branch Exec Source
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 #ifndef BOOST_JSON_DETAIL_CHARCONV_DETAIL_FROM_CHARS_FLOAT_IMPL_HPP
7 #define BOOST_JSON_DETAIL_CHARCONV_DETAIL_FROM_CHARS_FLOAT_IMPL_HPP
8
9 #include <boost/json/detail/charconv/detail/config.hpp>
10 #include <boost/json/detail/charconv/detail/from_chars_result.hpp>
11 #include <boost/json/detail/charconv/detail/parser.hpp>
12 #include <boost/json/detail/charconv/detail/compute_float64.hpp>
13 #include <boost/json/detail/charconv/chars_format.hpp>
14 #include <system_error>
15 #include <cstdlib>
16 #include <cmath>
17
18 namespace boost { namespace json { namespace detail { namespace charconv { namespace detail {
19
20 #ifdef BOOST_MSVC
21 # pragma warning(push)
22 # pragma warning(disable: 4244) // Implict converion when BOOST_IF_CONSTEXPR expands to if
23 #elif defined(__GNUC__) && __GNUC__ < 5 && !defined(__clang__)
24 # pragma GCC diagnostic push
25 # pragma GCC diagnostic ignored "-Wmissing-field-initializers"
26 #endif
27
28 template <typename T>
29 from_chars_result from_chars_strtod_impl(const char* first, const char* last, T& value, char* buffer) noexcept
30 {
31 // For strto(f/d)
32 // Floating point value corresponding to the contents of str on success.
33 // If the converted value falls out of range of corresponding return type, range error occurs and HUGE_VAL, HUGE_VALF or HUGE_VALL is returned.
34 // If no conversion can be performed, 0 is returned and *str_end is set to str.
35
36 std::memcpy(buffer, first, static_cast<std::size_t>(last - first));
37 buffer[last - first] = '\0';
38
39 char* str_end;
40 T return_value {};
41 BOOST_IF_CONSTEXPR (std::is_same<T, float>::value)
42 {
43 return_value = std::strtof(buffer, &str_end);
44 if (return_value == HUGE_VALF)
45 {
46 return {last, std::errc::result_out_of_range};
47 }
48 }
49 else BOOST_IF_CONSTEXPR (std::is_same<T, double>::value)
50 {
51 return_value = std::strtod(buffer, &str_end);
52 if (return_value == HUGE_VAL)
53 {
54 return {last, std::errc::result_out_of_range};
55 }
56 }
57 else
58 {
59 return_value = std::strtold(buffer, &str_end);
60 if (return_value == HUGE_VALL)
61 {
62 return {last, std::errc::result_out_of_range};
63 }
64 }
65
66 // Since this is a fallback routine we are safe to check for 0
67 if (return_value == 0 && str_end == last)
68 {
69 return {first, std::errc::result_out_of_range};
70 }
71
72 value = return_value;
73 return {first + (str_end - buffer), std::errc()};
74 }
75
76 template <typename T>
77 inline from_chars_result from_chars_strtod(const char* first, const char* last, T& value) noexcept
78 {
79 if (last - first < 1024)
80 {
81 char buffer[1024];
82 return from_chars_strtod_impl(first, last, value, buffer);
83 }
84
85 // If the string to be parsed does not fit into the 1024 byte static buffer than we have to allocate a buffer.
86 // malloc is used here because it does not throw on allocation failure.
87
88 char* buffer = static_cast<char*>(std::malloc(last - first + 1));
89 if (buffer == nullptr)
90 {
91 return {first, std::errc::not_enough_memory};
92 }
93
94 auto r = from_chars_strtod_impl(first, last, value, buffer);
95 std::free(buffer);
96
97 return r;
98 }
99
100 template <typename T>
101 from_chars_result from_chars_float_impl(const char* first, const char* last, T& value, chars_format fmt) noexcept
102 {
103 bool sign {};
104 std::uint64_t significand {};
105 std::int64_t exponent {};
106
107 auto r = charconv::detail::parser(first, last, sign, significand, exponent, fmt);
108 if (r.ec != std::errc())
109 {
110 return r;
111 }
112 else if (significand == 0)
113 {
114 value = sign ? static_cast<T>(-0.0L) : static_cast<T>(0.0L);
115 return r;
116 }
117 else if (exponent == -1)
118 {
119 // A full length significand e.g. -1985444280612224 with a power of -1 sometimes
120 // fails in compute_float64 but is trivial to calculate
121 // Found investigating GitHub issue #47
122 value = (sign ? -static_cast<T>(significand) : static_cast<T>(significand)) / 10;
123 }
124
125 bool success {};
126 T return_val {};
127 return_val = compute_float64(exponent, significand, sign, success);
128
129 if (!success)
130 {
131 if (significand == 1 && exponent == 0)
132 {
133 value = 1;
134 r.ptr = last;
135 r.ec = std::errc();
136 }
137 else
138 {
139 if (return_val == HUGE_VAL || return_val == -HUGE_VAL)
140 {
141 value = return_val;
142 r.ec = std::errc::result_out_of_range;
143 }
144 else if (exponent < -342)
145 {
146 value = sign ? -0.0 : 0.0;
147 r.ec = std::errc::result_out_of_range;
148 }
149 else
150 {
151 r = from_chars_strtod(first, r.ptr, value);
152 }
153 }
154 }
155 else
156 {
157 value = return_val;
158 }
159
160 return r;
161 }
162
163
164 #ifdef BOOST_MSVC
165 # pragma warning(pop)
166 #elif defined(__GNUC__) && __GNUC__ < 5 && !defined(__clang__)
167 # pragma GCC diagnostic pop
168 #endif
169
170 }}}}} // Namespace boost::charconv::detail
171
172 #endif // BOOST_JSON_DETAIL_CHARCONV_DETAIL_FROM_CHARS_FLOAT_IMPL_HPP
173