0.00% Lines (0/162)
0.00% Functions (0/4)
| TLA | Baseline | Branch | ||||||
|---|---|---|---|---|---|---|---|---|
| Line | Hits | Code | Line | Hits | Code | |||
| 1 | // Copyright 2023 Matt Borland | 1 | // Copyright 2023 Matt Borland | |||||
| 2 | // Distributed under the Boost Software License, Version 1.0. | 2 | // Distributed under the Boost Software License, Version 1.0. | |||||
| 3 | // https://www.boost.org/LICENSE_1_0.txt | 3 | // https://www.boost.org/LICENSE_1_0.txt | |||||
| 4 | 4 | |||||||
| 5 | #ifndef BOOST_JSON_DETAIL_CHARCONV_DETAIL_PARSER_HPP | 5 | #ifndef BOOST_JSON_DETAIL_CHARCONV_DETAIL_PARSER_HPP | |||||
| 6 | #define BOOST_JSON_DETAIL_CHARCONV_DETAIL_PARSER_HPP | 6 | #define BOOST_JSON_DETAIL_CHARCONV_DETAIL_PARSER_HPP | |||||
| 7 | 7 | |||||||
| 8 | #include <boost/json/detail/charconv/detail/config.hpp> | 8 | #include <boost/json/detail/charconv/detail/config.hpp> | |||||
| 9 | #include <boost/json/detail/charconv/detail/from_chars_result.hpp> | 9 | #include <boost/json/detail/charconv/detail/from_chars_result.hpp> | |||||
| 10 | #include <boost/json/detail/charconv/detail/from_chars_integer_impl.hpp> | 10 | #include <boost/json/detail/charconv/detail/from_chars_integer_impl.hpp> | |||||
| 11 | #include <boost/json/detail/charconv/detail/integer_search_trees.hpp> | 11 | #include <boost/json/detail/charconv/detail/integer_search_trees.hpp> | |||||
| 12 | #include <boost/json/detail/charconv/limits.hpp> | 12 | #include <boost/json/detail/charconv/limits.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 <type_traits> | 15 | #include <type_traits> | |||||
| 16 | #include <limits> | 16 | #include <limits> | |||||
| 17 | #include <cerrno> | 17 | #include <cerrno> | |||||
| 18 | #include <cstdint> | 18 | #include <cstdint> | |||||
| 19 | #include <cstring> | 19 | #include <cstring> | |||||
| 20 | 20 | |||||||
| 21 | #if defined(__GNUC__) && __GNUC__ < 5 && !defined(__clang__) | 21 | #if defined(__GNUC__) && __GNUC__ < 5 && !defined(__clang__) | |||||
| 22 | # pragma GCC diagnostic push | 22 | # pragma GCC diagnostic push | |||||
| 23 | # pragma GCC diagnostic ignored "-Wmissing-field-initializers" | 23 | # pragma GCC diagnostic ignored "-Wmissing-field-initializers" | |||||
| 24 | #endif | 24 | #endif | |||||
| 25 | 25 | |||||||
| 26 | namespace boost { namespace json { namespace detail { namespace charconv { namespace detail { | 26 | namespace boost { namespace json { namespace detail { namespace charconv { namespace detail { | |||||
| 27 | 27 | |||||||
| MISUBC | 28 | ✗ | inline bool is_integer_char(char c) noexcept | 28 | ✗ | inline bool is_integer_char(char c) noexcept | ||
| 29 | { | 29 | { | |||||
| MISUBC | 30 | ✗ | return (c >= '0') && (c <= '9'); | 30 | ✗ | return (c >= '0') && (c <= '9'); | ||
| 31 | } | 31 | } | |||||
| 32 | 32 | |||||||
| MISUBC | 33 | ✗ | inline bool is_hex_char(char c) noexcept | 33 | ✗ | inline bool is_hex_char(char c) noexcept | ||
| 34 | { | 34 | { | |||||
| MISUBC | 35 | ✗ | return is_integer_char(c) || (((c >= 'a') && (c <= 'f')) || ((c >= 'A') && (c <= 'F'))); | 35 | ✗ | return is_integer_char(c) || (((c >= 'a') && (c <= 'f')) || ((c >= 'A') && (c <= 'F'))); | ||
| 36 | } | 36 | } | |||||
| 37 | 37 | |||||||
| MISUBC | 38 | ✗ | inline bool is_delimiter(char c, chars_format fmt) noexcept | 38 | ✗ | inline bool is_delimiter(char c, chars_format fmt) noexcept | ||
| 39 | { | 39 | { | |||||
| MISUBC | 40 | ✗ | if (fmt != chars_format::hex) | 40 | ✗ | if (fmt != chars_format::hex) | ||
| 41 | { | 41 | { | |||||
| MISUBC | 42 | ✗ | return !is_integer_char(c) && c != 'e' && c != 'E'; | 42 | ✗ | return !is_integer_char(c) && c != 'e' && c != 'E'; | ||
| 43 | } | 43 | } | |||||
| 44 | 44 | |||||||
| MISUBC | 45 | ✗ | return !is_hex_char(c) && c != 'p' && c != 'P'; | 45 | ✗ | return !is_hex_char(c) && c != 'p' && c != 'P'; | ||
| 46 | } | 46 | } | |||||
| 47 | 47 | |||||||
| 48 | template <typename Unsigned_Integer, typename Integer> | 48 | template <typename Unsigned_Integer, typename Integer> | |||||
| MISUBC | 49 | ✗ | inline from_chars_result parser(const char* first, const char* last, bool& sign, Unsigned_Integer& significand, Integer& exponent, chars_format fmt = chars_format::general) noexcept | 49 | ✗ | inline from_chars_result parser(const char* first, const char* last, bool& sign, Unsigned_Integer& significand, Integer& exponent, chars_format fmt = chars_format::general) noexcept | ||
| 50 | { | 50 | { | |||||
| MISUBC | 51 | ✗ | if (first > last) | 51 | ✗ | if (first > last) | ||
| 52 | { | 52 | { | |||||
| MISUBC | 53 | ✗ | return {first, std::errc::invalid_argument}; | 53 | ✗ | return {first, std::errc::invalid_argument}; | ||
| 54 | } | 54 | } | |||||
| 55 | 55 | |||||||
| MISUBC | 56 | ✗ | auto next = first; | 56 | ✗ | auto next = first; | ||
| MISUBC | 57 | ✗ | bool all_zeros = true; | 57 | ✗ | bool all_zeros = true; | ||
| 58 | 58 | |||||||
| 59 | // First extract the sign | 59 | // First extract the sign | |||||
| MISUBC | 60 | ✗ | if (*next == '-') | 60 | ✗ | if (*next == '-') | ||
| 61 | { | 61 | { | |||||
| MISUBC | 62 | ✗ | sign = true; | 62 | ✗ | sign = true; | ||
| MISUBC | 63 | ✗ | ++next; | 63 | ✗ | ++next; | ||
| 64 | } | 64 | } | |||||
| MISUBC | 65 | ✗ | else if (*next == '+') | 65 | ✗ | else if (*next == '+') | ||
| 66 | { | 66 | { | |||||
| MISUBC | 67 | ✗ | return {next, std::errc::invalid_argument}; | 67 | ✗ | return {next, std::errc::invalid_argument}; | ||
| 68 | } | 68 | } | |||||
| 69 | else | 69 | else | |||||
| 70 | { | 70 | { | |||||
| MISUBC | 71 | ✗ | sign = false; | 71 | ✗ | sign = false; | ||
| 72 | } | 72 | } | |||||
| 73 | 73 | |||||||
| 74 | // Ignore leading zeros (e.g. 00005 or -002.3e+5) | 74 | // Ignore leading zeros (e.g. 00005 or -002.3e+5) | |||||
| MISUBC | 75 | ✗ | while (*next == '0' && next != last) | 75 | ✗ | while (*next == '0' && next != last) | ||
| 76 | { | 76 | { | |||||
| MISUBC | 77 | ✗ | ++next; | 77 | ✗ | ++next; | ||
| 78 | } | 78 | } | |||||
| 79 | 79 | |||||||
| 80 | // If the number is 0 we can abort now | 80 | // If the number is 0 we can abort now | |||||
| 81 | char exp_char; | 81 | char exp_char; | |||||
| 82 | char capital_exp_char; | 82 | char capital_exp_char; | |||||
| MISUBC | 83 | ✗ | if (fmt != chars_format::hex) | 83 | ✗ | if (fmt != chars_format::hex) | ||
| 84 | { | 84 | { | |||||
| MISUBC | 85 | ✗ | exp_char = 'e'; | 85 | ✗ | exp_char = 'e'; | ||
| MISUBC | 86 | ✗ | capital_exp_char = 'E'; | 86 | ✗ | capital_exp_char = 'E'; | ||
| 87 | } | 87 | } | |||||
| 88 | else | 88 | else | |||||
| 89 | { | 89 | { | |||||
| MISUBC | 90 | ✗ | exp_char = 'p'; | 90 | ✗ | exp_char = 'p'; | ||
| MISUBC | 91 | ✗ | capital_exp_char = 'P'; | 91 | ✗ | capital_exp_char = 'P'; | ||
| 92 | } | 92 | } | |||||
| 93 | 93 | |||||||
| MISUBC | 94 | ✗ | if (next == last || *next == exp_char || *next == -capital_exp_char) | 94 | ✗ | if (next == last || *next == exp_char || *next == -capital_exp_char) | ||
| 95 | { | 95 | { | |||||
| MISUBC | 96 | ✗ | significand = 0; | 96 | ✗ | significand = 0; | ||
| MISUBC | 97 | ✗ | exponent = 0; | 97 | ✗ | exponent = 0; | ||
| MISUBC | 98 | ✗ | return {next, std::errc()}; | 98 | ✗ | return {next, std::errc()}; | ||
| 99 | } | 99 | } | |||||
| 100 | 100 | |||||||
| 101 | // Next we get the significand | 101 | // Next we get the significand | |||||
| MISUBC | 102 | ✗ | constexpr std::size_t significand_buffer_size = limits<Unsigned_Integer>::max_chars10 - 1; // Base 10 or 16 | 102 | ✗ | constexpr std::size_t significand_buffer_size = limits<Unsigned_Integer>::max_chars10 - 1; // Base 10 or 16 | ||
| MISUBC | 103 | ✗ | char significand_buffer[significand_buffer_size] {}; | 103 | ✗ | char significand_buffer[significand_buffer_size] {}; | ||
| MISUBC | 104 | ✗ | std::size_t i = 0; | 104 | ✗ | std::size_t i = 0; | ||
| MISUBC | 105 | ✗ | std::size_t dot_position = 0; | 105 | ✗ | std::size_t dot_position = 0; | ||
| MISUBC | 106 | ✗ | Integer extra_zeros = 0; | 106 | ✗ | Integer extra_zeros = 0; | ||
| MISUBC | 107 | ✗ | Integer leading_zero_powers = 0; | 107 | ✗ | Integer leading_zero_powers = 0; | ||
| MISUBC | 108 | ✗ | const auto char_validation_func = (fmt != charconv::chars_format::hex) ? is_integer_char : is_hex_char; | 108 | ✗ | const auto char_validation_func = (fmt != charconv::chars_format::hex) ? is_integer_char : is_hex_char; | ||
| MISUBC | 109 | ✗ | const int base = (fmt != charconv::chars_format::hex) ? 10 : 16; | 109 | ✗ | const int base = (fmt != charconv::chars_format::hex) ? 10 : 16; | ||
| 110 | 110 | |||||||
| MISUBC | 111 | ✗ | while (char_validation_func(*next) && next != last && i < significand_buffer_size) | 111 | ✗ | while (char_validation_func(*next) && next != last && i < significand_buffer_size) | ||
| 112 | { | 112 | { | |||||
| MISUBC | 113 | ✗ | all_zeros = false; | 113 | ✗ | all_zeros = false; | ||
| MISUBC | 114 | ✗ | significand_buffer[i] = *next; | 114 | ✗ | significand_buffer[i] = *next; | ||
| MISUBC | 115 | ✗ | ++next; | 115 | ✗ | ++next; | ||
| MISUBC | 116 | ✗ | ++i; | 116 | ✗ | ++i; | ||
| 117 | } | 117 | } | |||||
| 118 | 118 | |||||||
| MISUBC | 119 | ✗ | bool fractional = false; | 119 | ✗ | bool fractional = false; | ||
| MISUBC | 120 | ✗ | if (next == last) | 120 | ✗ | if (next == last) | ||
| 121 | { | 121 | { | |||||
| 122 | // if fmt is chars_format::scientific the e is required | 122 | // if fmt is chars_format::scientific the e is required | |||||
| MISUBC | 123 | ✗ | if (fmt == chars_format::scientific) | 123 | ✗ | if (fmt == chars_format::scientific) | ||
| 124 | { | 124 | { | |||||
| MISUBC | 125 | ✗ | return {first, std::errc::invalid_argument}; | 125 | ✗ | return {first, std::errc::invalid_argument}; | ||
| 126 | } | 126 | } | |||||
| 127 | 127 | |||||||
| MISUBC | 128 | ✗ | exponent = 0; | 128 | ✗ | exponent = 0; | ||
| MISUBC | 129 | ✗ | std::size_t offset = i; | 129 | ✗ | std::size_t offset = i; | ||
| 130 | 130 | |||||||
| MISUBC | 131 | ✗ | from_chars_result r = from_chars(significand_buffer, significand_buffer + offset, significand, base); | 131 | ✗ | from_chars_result r = from_chars(significand_buffer, significand_buffer + offset, significand, base); | ||
| MISUBC | 132 | ✗ | switch (r.ec) | 132 | ✗ | switch (r.ec) | ||
| 133 | { | 133 | { | |||||
| MISUBC | 134 | ✗ | case std::errc::invalid_argument: | 134 | ✗ | case std::errc::invalid_argument: | ||
| MISUBC | 135 | ✗ | return {first, std::errc::invalid_argument}; | 135 | ✗ | return {first, std::errc::invalid_argument}; | ||
| MISUBC | 136 | ✗ | case std::errc::result_out_of_range: | 136 | ✗ | case std::errc::result_out_of_range: | ||
| MISUBC | 137 | ✗ | return {next, std::errc::result_out_of_range}; | 137 | ✗ | return {next, std::errc::result_out_of_range}; | ||
| MISUBC | 138 | ✗ | default: | 138 | ✗ | default: | ||
| MISUBC | 139 | ✗ | return {next, std::errc()}; | 139 | ✗ | return {next, std::errc()}; | ||
| 140 | } | 140 | } | |||||
| 141 | } | 141 | } | |||||
| MISUBC | 142 | ✗ | else if (*next == '.') | 142 | ✗ | else if (*next == '.') | ||
| 143 | { | 143 | { | |||||
| MISUBC | 144 | ✗ | ++next; | 144 | ✗ | ++next; | ||
| MISUBC | 145 | ✗ | fractional = true; | 145 | ✗ | fractional = true; | ||
| MISUBC | 146 | ✗ | dot_position = i; | 146 | ✗ | dot_position = i; | ||
| 147 | 147 | |||||||
| 148 | // Process the fractional part if we have it | 148 | // Process the fractional part if we have it | |||||
| 149 | // | 149 | // | |||||
| 150 | // if fmt is chars_format::scientific the e is required | 150 | // if fmt is chars_format::scientific the e is required | |||||
| 151 | // if fmt is chars_format::fixed and not scientific the e is disallowed | 151 | // if fmt is chars_format::fixed and not scientific the e is disallowed | |||||
| 152 | // if fmt is chars_format::general (which is scientific and fixed) the e is optional | 152 | // if fmt is chars_format::general (which is scientific and fixed) the e is optional | |||||
| 153 | 153 | |||||||
| 154 | // If we have the value 0.00001 we can continue to chop zeros and adjust the exponent | 154 | // If we have the value 0.00001 we can continue to chop zeros and adjust the exponent | |||||
| 155 | // so that we get the useful parts of the fraction | 155 | // so that we get the useful parts of the fraction | |||||
| MISUBC | 156 | ✗ | if (all_zeros) | 156 | ✗ | if (all_zeros) | ||
| 157 | { | 157 | { | |||||
| MISUBC | 158 | ✗ | while (*next == '0' && next != last) | 158 | ✗ | while (*next == '0' && next != last) | ||
| 159 | { | 159 | { | |||||
| MISUBC | 160 | ✗ | ++next; | 160 | ✗ | ++next; | ||
| MISUBC | 161 | ✗ | --leading_zero_powers; | 161 | ✗ | --leading_zero_powers; | ||
| 162 | } | 162 | } | |||||
| 163 | 163 | |||||||
| MISUBC | 164 | ✗ | if (next == last) | 164 | ✗ | if (next == last) | ||
| 165 | { | 165 | { | |||||
| MISUBC | 166 | ✗ | return {last, std::errc()}; | 166 | ✗ | return {last, std::errc()}; | ||
| 167 | } | 167 | } | |||||
| 168 | } | 168 | } | |||||
| 169 | 169 | |||||||
| MISUBC | 170 | ✗ | while (char_validation_func(*next) && next != last && i < significand_buffer_size) | 170 | ✗ | while (char_validation_func(*next) && next != last && i < significand_buffer_size) | ||
| 171 | { | 171 | { | |||||
| MISUBC | 172 | ✗ | significand_buffer[i] = *next; | 172 | ✗ | significand_buffer[i] = *next; | ||
| MISUBC | 173 | ✗ | ++next; | 173 | ✗ | ++next; | ||
| MISUBC | 174 | ✗ | ++i; | 174 | ✗ | ++i; | ||
| 175 | } | 175 | } | |||||
| 176 | } | 176 | } | |||||
| 177 | 177 | |||||||
| MISUBC | 178 | ✗ | if (i == significand_buffer_size) | 178 | ✗ | if (i == significand_buffer_size) | ||
| 179 | { | 179 | { | |||||
| 180 | // We can not process any more significant figures into the significand so skip to the end | 180 | // We can not process any more significant figures into the significand so skip to the end | |||||
| 181 | // or the exponent part and capture the additional orders of magnitude for the exponent | 181 | // or the exponent part and capture the additional orders of magnitude for the exponent | |||||
| MISUBC | 182 | ✗ | bool found_dot = false; | 182 | ✗ | bool found_dot = false; | ||
| MISUBC | 183 | ✗ | while ((char_validation_func(*next) || *next == '.') && next != last) | 183 | ✗ | while ((char_validation_func(*next) || *next == '.') && next != last) | ||
| 184 | { | 184 | { | |||||
| MISUBC | 185 | ✗ | ++next; | 185 | ✗ | ++next; | ||
| MISUBC | 186 | ✗ | if (!fractional && !found_dot) | 186 | ✗ | if (!fractional && !found_dot) | ||
| 187 | { | 187 | { | |||||
| MISUBC | 188 | ✗ | ++extra_zeros; | 188 | ✗ | ++extra_zeros; | ||
| 189 | } | 189 | } | |||||
| MISUBC | 190 | ✗ | if (*next == '.') | 190 | ✗ | if (*next == '.') | ||
| 191 | { | 191 | { | |||||
| MISUBC | 192 | ✗ | found_dot = true; | 192 | ✗ | found_dot = true; | ||
| 193 | } | 193 | } | |||||
| 194 | } | 194 | } | |||||
| 195 | } | 195 | } | |||||
| 196 | 196 | |||||||
| MISUBC | 197 | ✗ | if (next == last || is_delimiter(*next, fmt)) | 197 | ✗ | if (next == last || is_delimiter(*next, fmt)) | ||
| 198 | { | 198 | { | |||||
| MISUBC | 199 | ✗ | if (fmt == chars_format::scientific) | 199 | ✗ | if (fmt == chars_format::scientific) | ||
| 200 | { | 200 | { | |||||
| MISUBC | 201 | ✗ | return {first, std::errc::invalid_argument}; | 201 | ✗ | return {first, std::errc::invalid_argument}; | ||
| 202 | } | 202 | } | |||||
| MISUBC | 203 | ✗ | if (dot_position != 0 || fractional) | 203 | ✗ | if (dot_position != 0 || fractional) | ||
| 204 | { | 204 | { | |||||
| MISUBC | 205 | ✗ | exponent = static_cast<Integer>(dot_position) - i + extra_zeros + leading_zero_powers; | 205 | ✗ | exponent = static_cast<Integer>(dot_position) - i + extra_zeros + leading_zero_powers; | ||
| 206 | } | 206 | } | |||||
| 207 | else | 207 | else | |||||
| 208 | { | 208 | { | |||||
| MISUBC | 209 | ✗ | exponent = extra_zeros + leading_zero_powers; | 209 | ✗ | exponent = extra_zeros + leading_zero_powers; | ||
| 210 | } | 210 | } | |||||
| MISUBC | 211 | ✗ | std::size_t offset = i; | 211 | ✗ | std::size_t offset = i; | ||
| 212 | 212 | |||||||
| MISUBC | 213 | ✗ | from_chars_result r = from_chars(significand_buffer, significand_buffer + offset, significand, base); | 213 | ✗ | from_chars_result r = from_chars(significand_buffer, significand_buffer + offset, significand, base); | ||
| MISUBC | 214 | ✗ | switch (r.ec) | 214 | ✗ | switch (r.ec) | ||
| 215 | { | 215 | { | |||||
| MISUBC | 216 | ✗ | case std::errc::invalid_argument: | 216 | ✗ | case std::errc::invalid_argument: | ||
| MISUBC | 217 | ✗ | return {first, std::errc::invalid_argument}; | 217 | ✗ | return {first, std::errc::invalid_argument}; | ||
| MISUBC | 218 | ✗ | case std::errc::result_out_of_range: | 218 | ✗ | case std::errc::result_out_of_range: | ||
| MISUBC | 219 | ✗ | return {next, std::errc::result_out_of_range}; | 219 | ✗ | return {next, std::errc::result_out_of_range}; | ||
| MISUBC | 220 | ✗ | default: | 220 | ✗ | default: | ||
| MISUBC | 221 | ✗ | return {next, std::errc()}; | 221 | ✗ | return {next, std::errc()}; | ||
| 222 | } | 222 | } | |||||
| 223 | } | 223 | } | |||||
| MISUBC | 224 | ✗ | else if (*next == exp_char || *next == capital_exp_char) | 224 | ✗ | else if (*next == exp_char || *next == capital_exp_char) | ||
| 225 | { | 225 | { | |||||
| 226 | // Would be a number without a significand e.g. e+03 | 226 | // Would be a number without a significand e.g. e+03 | |||||
| MISUBC | 227 | ✗ | if (next == first) | 227 | ✗ | if (next == first) | ||
| 228 | { | 228 | { | |||||
| MISUBC | 229 | ✗ | return {next, std::errc::invalid_argument}; | 229 | ✗ | return {next, std::errc::invalid_argument}; | ||
| 230 | } | 230 | } | |||||
| 231 | 231 | |||||||
| MISUBC | 232 | ✗ | ++next; | 232 | ✗ | ++next; | ||
| MISUBC | 233 | ✗ | if (fmt == chars_format::fixed) | 233 | ✗ | if (fmt == chars_format::fixed) | ||
| 234 | { | 234 | { | |||||
| MISUBC | 235 | ✗ | return {first, std::errc::invalid_argument}; | 235 | ✗ | return {first, std::errc::invalid_argument}; | ||
| 236 | } | 236 | } | |||||
| 237 | 237 | |||||||
| MISUBC | 238 | ✗ | exponent = i - 1; | 238 | ✗ | exponent = i - 1; | ||
| MISUBC | 239 | ✗ | std::size_t offset = i; | 239 | ✗ | std::size_t offset = i; | ||
| MISUBC | 240 | ✗ | bool round = false; | 240 | ✗ | bool round = false; | ||
| 241 | // If more digits are present than representable in the significand of the target type | 241 | // If more digits are present than representable in the significand of the target type | |||||
| 242 | // we set the maximum | 242 | // we set the maximum | |||||
| MISUBC | 243 | ✗ | if (offset > significand_buffer_size) | 243 | ✗ | if (offset > significand_buffer_size) | ||
| 244 | { | 244 | { | |||||
| MISUBC | 245 | ✗ | offset = significand_buffer_size - 1; | 245 | ✗ | offset = significand_buffer_size - 1; | ||
| MISUBC | 246 | ✗ | i = significand_buffer_size; | 246 | ✗ | i = significand_buffer_size; | ||
| MISUBC | 247 | ✗ | if (significand_buffer[offset] == '5' || | 247 | ✗ | if (significand_buffer[offset] == '5' || | ||
| MISUBC | 248 | ✗ | significand_buffer[offset] == '6' || | 248 | ✗ | significand_buffer[offset] == '6' || | ||
| MISUBC | 249 | ✗ | significand_buffer[offset] == '7' || | 249 | ✗ | significand_buffer[offset] == '7' || | ||
| MISUBC | 250 | ✗ | significand_buffer[offset] == '8' || | 250 | ✗ | significand_buffer[offset] == '8' || | ||
| MISUBC | 251 | ✗ | significand_buffer[offset] == '9') | 251 | ✗ | significand_buffer[offset] == '9') | ||
| 252 | { | 252 | { | |||||
| MISUBC | 253 | ✗ | round = true; | 253 | ✗ | round = true; | ||
| 254 | } | 254 | } | |||||
| 255 | } | 255 | } | |||||
| 256 | 256 | |||||||
| 257 | // If the significand is 0 from chars will return std::errc::invalid_argument because there is nothing in the buffer, | 257 | // If the significand is 0 from chars will return std::errc::invalid_argument because there is nothing in the buffer, | |||||
| 258 | // but it is a valid value. We need to continue parsing to get the correct value of ptr even | 258 | // but it is a valid value. We need to continue parsing to get the correct value of ptr even | |||||
| 259 | // though we know we could bail now. | 259 | // though we know we could bail now. | |||||
| 260 | // | 260 | // | |||||
| 261 | // See GitHub issue #29: https://github.com/cppalliance/charconv/issues/29 | 261 | // See GitHub issue #29: https://github.com/cppalliance/charconv/issues/29 | |||||
| MISUBC | 262 | ✗ | if (offset != 0) | 262 | ✗ | if (offset != 0) | ||
| 263 | { | 263 | { | |||||
| MISUBC | 264 | ✗ | from_chars_result r = from_chars(significand_buffer, significand_buffer + offset, significand, base); | 264 | ✗ | from_chars_result r = from_chars(significand_buffer, significand_buffer + offset, significand, base); | ||
| MISUBC | 265 | ✗ | switch (r.ec) | 265 | ✗ | switch (r.ec) | ||
| 266 | { | 266 | { | |||||
| MISUBC | 267 | ✗ | case std::errc::invalid_argument: | 267 | ✗ | case std::errc::invalid_argument: | ||
| MISUBC | 268 | ✗ | return {first, std::errc::invalid_argument}; | 268 | ✗ | return {first, std::errc::invalid_argument}; | ||
| MISUBC | 269 | ✗ | case std::errc::result_out_of_range: | 269 | ✗ | case std::errc::result_out_of_range: | ||
| MISUBC | 270 | ✗ | return {next, std::errc::result_out_of_range}; | 270 | ✗ | return {next, std::errc::result_out_of_range}; | ||
| MISUBC | 271 | ✗ | default: | 271 | ✗ | default: | ||
| MISUBC | 272 | ✗ | break; | 272 | ✗ | break; | ||
| 273 | } | 273 | } | |||||
| 274 | 274 | |||||||
| MISUBC | 275 | ✗ | if (round) | 275 | ✗ | if (round) | ||
| 276 | { | 276 | { | |||||
| MISUBC | 277 | ✗ | significand += 1; | 277 | ✗ | significand += 1; | ||
| 278 | } | 278 | } | |||||
| 279 | } | 279 | } | |||||
| MISUBC | 280 | ✗ | } | 280 | ✗ | } | ||
| 281 | else | 281 | else | |||||
| 282 | { | 282 | { | |||||
| MISUBC | 283 | ✗ | return {first, std::errc::invalid_argument}; | 283 | ✗ | return {first, std::errc::invalid_argument}; | ||
| 284 | } | 284 | } | |||||
| 285 | 285 | |||||||
| 286 | // Finally we get the exponent | 286 | // Finally we get the exponent | |||||
| MISUBC | 287 | ✗ | constexpr std::size_t exponent_buffer_size = 6; // Float128 min exp is −16382 | 287 | ✗ | constexpr std::size_t exponent_buffer_size = 6; // Float128 min exp is −16382 | ||
| MISUBC | 288 | ✗ | char exponent_buffer[exponent_buffer_size] {}; | 288 | ✗ | char exponent_buffer[exponent_buffer_size] {}; | ||
| MISUBC | 289 | ✗ | Integer significand_digits = i; | 289 | ✗ | Integer significand_digits = i; | ||
| MISUBC | 290 | ✗ | i = 0; | 290 | ✗ | i = 0; | ||
| 291 | 291 | |||||||
| 292 | // Get the sign first | 292 | // Get the sign first | |||||
| MISUBC | 293 | ✗ | if (*next == '-') | 293 | ✗ | if (*next == '-') | ||
| 294 | { | 294 | { | |||||
| MISUBC | 295 | ✗ | exponent_buffer[i] = *next; | 295 | ✗ | exponent_buffer[i] = *next; | ||
| MISUBC | 296 | ✗ | ++next; | 296 | ✗ | ++next; | ||
| MISUBC | 297 | ✗ | ++i; | 297 | ✗ | ++i; | ||
| 298 | } | 298 | } | |||||
| MISUBC | 299 | ✗ | else if (*next == '+') | 299 | ✗ | else if (*next == '+') | ||
| 300 | { | 300 | { | |||||
| MISUBC | 301 | ✗ | ++next; | 301 | ✗ | ++next; | ||
| 302 | } | 302 | } | |||||
| 303 | 303 | |||||||
| 304 | // Next strip any leading zeros | 304 | // Next strip any leading zeros | |||||
| MISUBC | 305 | ✗ | while (*next == '0') | 305 | ✗ | while (*next == '0') | ||
| 306 | { | 306 | { | |||||
| MISUBC | 307 | ✗ | ++next; | 307 | ✗ | ++next; | ||
| 308 | } | 308 | } | |||||
| 309 | 309 | |||||||
| 310 | // Process the significant values | 310 | // Process the significant values | |||||
| MISUBC | 311 | ✗ | while (is_integer_char(*next) && next != last && i < exponent_buffer_size) | 311 | ✗ | while (is_integer_char(*next) && next != last && i < exponent_buffer_size) | ||
| 312 | { | 312 | { | |||||
| MISUBC | 313 | ✗ | exponent_buffer[i] = *next; | 313 | ✗ | exponent_buffer[i] = *next; | ||
| MISUBC | 314 | ✗ | ++next; | 314 | ✗ | ++next; | ||
| MISUBC | 315 | ✗ | ++i; | 315 | ✗ | ++i; | ||
| 316 | } | 316 | } | |||||
| 317 | 317 | |||||||
| 318 | // If the exponent can't fit in the buffer the number is not representable | 318 | // If the exponent can't fit in the buffer the number is not representable | |||||
| MISUBC | 319 | ✗ | if (next != last && i == exponent_buffer_size) | 319 | ✗ | if (next != last && i == exponent_buffer_size) | ||
| 320 | { | 320 | { | |||||
| MISUBC | 321 | ✗ | return {next, std::errc::result_out_of_range}; | 321 | ✗ | return {next, std::errc::result_out_of_range}; | ||
| 322 | } | 322 | } | |||||
| 323 | 323 | |||||||
| 324 | // If the exponent was e+00 or e-00 | 324 | // If the exponent was e+00 or e-00 | |||||
| MISUBC | 325 | ✗ | if (i == 0 || (i == 1 && exponent_buffer[0] == '-')) | 325 | ✗ | if (i == 0 || (i == 1 && exponent_buffer[0] == '-')) | ||
| 326 | { | 326 | { | |||||
| MISUBC | 327 | ✗ | if (fractional) | 327 | ✗ | if (fractional) | ||
| 328 | { | 328 | { | |||||
| MISUBC | 329 | ✗ | exponent = static_cast<Integer>(dot_position) - significand_digits; | 329 | ✗ | exponent = static_cast<Integer>(dot_position) - significand_digits; | ||
| 330 | } | 330 | } | |||||
| 331 | else | 331 | else | |||||
| 332 | { | 332 | { | |||||
| MISUBC | 333 | ✗ | exponent = extra_zeros; | 333 | ✗ | exponent = extra_zeros; | ||
| 334 | } | 334 | } | |||||
| 335 | 335 | |||||||
| MISUBC | 336 | ✗ | return {next, std::errc()}; | 336 | ✗ | return {next, std::errc()}; | ||
| 337 | } | 337 | } | |||||
| 338 | 338 | |||||||
| MISUBC | 339 | ✗ | const auto r = from_chars(exponent_buffer, exponent_buffer + i, exponent); | 339 | ✗ | const auto r = from_chars(exponent_buffer, exponent_buffer + i, exponent); | ||
| 340 | 340 | |||||||
| MISUBC | 341 | ✗ | exponent += leading_zero_powers; | 341 | ✗ | exponent += leading_zero_powers; | ||
| 342 | 342 | |||||||
| MISUBC | 343 | ✗ | switch (r.ec) | 343 | ✗ | switch (r.ec) | ||
| 344 | { | 344 | { | |||||
| MISUBC | 345 | ✗ | case std::errc::invalid_argument: | 345 | ✗ | case std::errc::invalid_argument: | ||
| MISUBC | 346 | ✗ | return {first, std::errc::invalid_argument}; | 346 | ✗ | return {first, std::errc::invalid_argument}; | ||
| MISUBC | 347 | ✗ | case std::errc::result_out_of_range: | 347 | ✗ | case std::errc::result_out_of_range: | ||
| MISUBC | 348 | ✗ | return {next, std::errc::result_out_of_range}; | 348 | ✗ | return {next, std::errc::result_out_of_range}; | ||
| MISUBC | 349 | ✗ | default: | 349 | ✗ | default: | ||
| MISUBC | 350 | ✗ | if (fractional) | 350 | ✗ | if (fractional) | ||
| 351 | { | 351 | { | |||||
| 352 | // Need to take the offset from 1.xxx because compute_floatXXX assumes the significand is an integer | 352 | // Need to take the offset from 1.xxx because compute_floatXXX assumes the significand is an integer | |||||
| 353 | // so the exponent is off by the number of digits in the significand - 1 | 353 | // so the exponent is off by the number of digits in the significand - 1 | |||||
| MISUBC | 354 | ✗ | if (fmt == chars_format::hex) | 354 | ✗ | if (fmt == chars_format::hex) | ||
| 355 | { | 355 | { | |||||
| 356 | // In hex the number of digits parsed is possibly less than the number of digits in base10 | 356 | // In hex the number of digits parsed is possibly less than the number of digits in base10 | |||||
| MISUBC | 357 | ✗ | exponent -= num_digits(significand) - dot_position; | 357 | ✗ | exponent -= num_digits(significand) - dot_position; | ||
| 358 | } | 358 | } | |||||
| 359 | else | 359 | else | |||||
| 360 | { | 360 | { | |||||
| MISUBC | 361 | ✗ | exponent -= significand_digits - dot_position; | 361 | ✗ | exponent -= significand_digits - dot_position; | ||
| 362 | } | 362 | } | |||||
| 363 | } | 363 | } | |||||
| 364 | else | 364 | else | |||||
| 365 | { | 365 | { | |||||
| MISUBC | 366 | ✗ | exponent += extra_zeros; | 366 | ✗ | exponent += extra_zeros; | ||
| 367 | } | 367 | } | |||||
| MISUBC | 368 | ✗ | return {next, std::errc()}; | 368 | ✗ | return {next, std::errc()}; | ||
| 369 | } | 369 | } | |||||
| 370 | } | 370 | } | |||||
| 371 | 371 | |||||||
| 372 | }}}}} // Namespaces | 372 | }}}}} // Namespaces | |||||
| 373 | 373 | |||||||
| 374 | #if defined(__GNUC__) && __GNUC__ < 5 && !defined(__clang__) | 374 | #if defined(__GNUC__) && __GNUC__ < 5 && !defined(__clang__) | |||||
| 375 | # pragma GCC diagnostic pop | 375 | # pragma GCC diagnostic pop | |||||
| 376 | #endif | 376 | #endif | |||||
| 377 | 377 | |||||||
| 378 | #endif // BOOST_JSON_DETAIL_CHARCONV_DETAIL_PARSER_HPP | 378 | #endif // BOOST_JSON_DETAIL_CHARCONV_DETAIL_PARSER_HPP | |||||