detail/charconv/detail/from_chars_float_impl.hpp

0.0% Lines (0/49) 0.0% List of functions (0/3)
from_chars_float_impl.hpp
f(x) Functions (3)
Line TLA Hits Source Code
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