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