87.96% Lines (95/108) 0.00% Functions (0/0)
TLA Baseline Branch
Line Hits Code Line Hits Code
1   // Copyright 2020-2023 Daniel Lemire 1   // Copyright 2020-2023 Daniel Lemire
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   // Derivative of: https://github.com/fastfloat/fast_float 6   // Derivative of: https://github.com/fastfloat/fast_float
7   7  
8   #ifndef BOOST_JSON_DETAIL_CHARCONV_DETAIL_FASTFLOAT_ASCII_NUMBER_HPP 8   #ifndef BOOST_JSON_DETAIL_CHARCONV_DETAIL_FASTFLOAT_ASCII_NUMBER_HPP
9   #define BOOST_JSON_DETAIL_CHARCONV_DETAIL_FASTFLOAT_ASCII_NUMBER_HPP 9   #define BOOST_JSON_DETAIL_CHARCONV_DETAIL_FASTFLOAT_ASCII_NUMBER_HPP
10   10  
11   #include <boost/endian/conversion.hpp> 11   #include <boost/endian/conversion.hpp>
12   #include <boost/json/detail/charconv/detail/fast_float/float_common.hpp> 12   #include <boost/json/detail/charconv/detail/fast_float/float_common.hpp>
13   #include <cctype> 13   #include <cctype>
14   #include <cstdint> 14   #include <cstdint>
15   #include <cstring> 15   #include <cstring>
16   #include <iterator> 16   #include <iterator>
17   17  
18   namespace boost { namespace json { namespace detail { namespace charconv { namespace detail { namespace fast_float { 18   namespace boost { namespace json { namespace detail { namespace charconv { namespace detail { namespace fast_float {
19   19  
20   // Next function can be micro-optimized, but compilers are entirely 20   // Next function can be micro-optimized, but compilers are entirely
21   // able to optimize it well. 21   // able to optimize it well.
22   template <typename UC> 22   template <typename UC>
23   BOOST_FORCEINLINE constexpr bool is_integer(UC c) noexcept { 23   BOOST_FORCEINLINE constexpr bool is_integer(UC c) noexcept {
HITCBC 24   29053321 return !(c > UC('9') || c < UC('0')); 24   29053321 return !(c > UC('9') || c < UC('0'));
25   } 25   }
26   26  
27   BOOST_FORCEINLINE constexpr uint64_t byteswap(uint64_t val) { 27   BOOST_FORCEINLINE constexpr uint64_t byteswap(uint64_t val) {
28   return (val & 0xFF00000000000000) >> 56 28   return (val & 0xFF00000000000000) >> 56
29   | (val & 0x00FF000000000000) >> 40 29   | (val & 0x00FF000000000000) >> 40
30   | (val & 0x0000FF0000000000) >> 24 30   | (val & 0x0000FF0000000000) >> 24
31   | (val & 0x000000FF00000000) >> 8 31   | (val & 0x000000FF00000000) >> 8
32   | (val & 0x00000000FF000000) << 8 32   | (val & 0x00000000FF000000) << 8
33   | (val & 0x0000000000FF0000) << 24 33   | (val & 0x0000000000FF0000) << 24
34   | (val & 0x000000000000FF00) << 40 34   | (val & 0x000000000000FF00) << 40
35   | (val & 0x00000000000000FF) << 56; 35   | (val & 0x00000000000000FF) << 56;
36   } 36   }
37   37  
38   BOOST_FORCEINLINE BOOST_JSON_FASTFLOAT_CONSTEXPR20 38   BOOST_FORCEINLINE BOOST_JSON_FASTFLOAT_CONSTEXPR20
39   uint64_t read_u64(const char *chars) { 39   uint64_t read_u64(const char *chars) {
HITCBC 40   4835760 if (cpp20_and_in_constexpr()) { 40   4835760 if (cpp20_and_in_constexpr()) {
MISUBC 41   uint64_t val = 0; 41   uint64_t val = 0;
MISUBC 42   for(int i = 0; i < 8; ++i) { 42   for(int i = 0; i < 8; ++i) {
MISUBC 43   val |= uint64_t(*chars) << (i*8); 43   val |= uint64_t(*chars) << (i*8);
MISUBC 44   ++chars; 44   ++chars;
45   } 45   }
MISUBC 46   return val; 46   return val;
47   } 47   }
48   uint64_t val; 48   uint64_t val;
HITCBC 49   4835760 ::memcpy(&val, chars, sizeof(uint64_t)); 49   4835760 ::memcpy(&val, chars, sizeof(uint64_t));
HITCBC 50   4835760 endian::little_to_native_inplace(val); 50   4835760 endian::little_to_native_inplace(val);
HITCBC 51   4835760 return val; 51   4835760 return val;
52   } 52   }
53   53  
54   BOOST_FORCEINLINE BOOST_JSON_FASTFLOAT_CONSTEXPR20 54   BOOST_FORCEINLINE BOOST_JSON_FASTFLOAT_CONSTEXPR20
55   void write_u64(uint8_t *chars, uint64_t val) { 55   void write_u64(uint8_t *chars, uint64_t val) {
56   if (cpp20_and_in_constexpr()) { 56   if (cpp20_and_in_constexpr()) {
57   for(int i = 0; i < 8; ++i) { 57   for(int i = 0; i < 8; ++i) {
58   *chars = uint8_t(val); 58   *chars = uint8_t(val);
59   val >>= 8; 59   val >>= 8;
60   ++chars; 60   ++chars;
61   } 61   }
62   return; 62   return;
63   } 63   }
64   endian::native_to_little_inplace(val); 64   endian::native_to_little_inplace(val);
65   ::memcpy(chars, &val, sizeof(uint64_t)); 65   ::memcpy(chars, &val, sizeof(uint64_t));
66   } 66   }
67   67  
68   // credit @aqrit 68   // credit @aqrit
69   BOOST_FORCEINLINE BOOST_JSON_CXX14_CONSTEXPR_NO_INLINE 69   BOOST_FORCEINLINE BOOST_JSON_CXX14_CONSTEXPR_NO_INLINE
70   uint32_t parse_eight_digits_unrolled(uint64_t val) { 70   uint32_t parse_eight_digits_unrolled(uint64_t val) {
HITCBC 71   2151895 constexpr uint64_t mask = 0x000000FF000000FF; 71   2151895 constexpr uint64_t mask = 0x000000FF000000FF;
HITCBC 72   2151895 constexpr uint64_t mul1 = 0x000F424000000064; // 100 + (1000000ULL << 32) 72   2151895 constexpr uint64_t mul1 = 0x000F424000000064; // 100 + (1000000ULL << 32)
HITCBC 73   2151895 constexpr uint64_t mul2 = 0x0000271000000001; // 1 + (10000ULL << 32) 73   2151895 constexpr uint64_t mul2 = 0x0000271000000001; // 1 + (10000ULL << 32)
HITCBC 74   2151895 val -= 0x3030303030303030; 74   2151895 val -= 0x3030303030303030;
HITCBC 75   2151895 val = (val * 10) + (val >> 8); // val = (val * 2561) >> 8; 75   2151895 val = (val * 10) + (val >> 8); // val = (val * 2561) >> 8;
HITCBC 76   2151895 val = (((val & mask) * mul1) + (((val >> 16) & mask) * mul2)) >> 32; 76   2151895 val = (((val & mask) * mul1) + (((val >> 16) & mask) * mul2)) >> 32;
HITCBC 77   2151895 return uint32_t(val); 77   2151895 return uint32_t(val);
78   } 78   }
79   79  
80   BOOST_FORCEINLINE constexpr 80   BOOST_FORCEINLINE constexpr
81   uint32_t parse_eight_digits_unrolled(const char16_t *) noexcept { 81   uint32_t parse_eight_digits_unrolled(const char16_t *) noexcept {
82   return 0; 82   return 0;
83   } 83   }
84   84  
85   BOOST_FORCEINLINE constexpr 85   BOOST_FORCEINLINE constexpr
86   uint32_t parse_eight_digits_unrolled(const char32_t *) noexcept { 86   uint32_t parse_eight_digits_unrolled(const char32_t *) noexcept {
87   return 0; 87   return 0;
88   } 88   }
89   89  
90   BOOST_FORCEINLINE BOOST_JSON_FASTFLOAT_CONSTEXPR20 90   BOOST_FORCEINLINE BOOST_JSON_FASTFLOAT_CONSTEXPR20
91   uint32_t parse_eight_digits_unrolled(const char *chars) noexcept { 91   uint32_t parse_eight_digits_unrolled(const char *chars) noexcept {
HITCBC 92   4303790 return parse_eight_digits_unrolled(read_u64(chars)); 92   4303790 return parse_eight_digits_unrolled(read_u64(chars));
93   } 93   }
94   94  
95   // credit @aqrit 95   // credit @aqrit
96   BOOST_FORCEINLINE constexpr bool is_made_of_eight_digits_fast(uint64_t val) noexcept { 96   BOOST_FORCEINLINE constexpr bool is_made_of_eight_digits_fast(uint64_t val) noexcept {
HITCBC 97   2683865 return !((((val + 0x4646464646464646) | (val - 0x3030303030303030)) & 0x8080808080808080)); 97   2683865 return !((((val + 0x4646464646464646) | (val - 0x3030303030303030)) & 0x8080808080808080));
98   } 98   }
99   99  
100   BOOST_FORCEINLINE constexpr 100   BOOST_FORCEINLINE constexpr
101   bool is_made_of_eight_digits_fast(const char16_t *) noexcept { 101   bool is_made_of_eight_digits_fast(const char16_t *) noexcept {
102   return false; 102   return false;
103   } 103   }
104   104  
105   BOOST_FORCEINLINE constexpr 105   BOOST_FORCEINLINE constexpr
106   bool is_made_of_eight_digits_fast(const char32_t *) noexcept { 106   bool is_made_of_eight_digits_fast(const char32_t *) noexcept {
107   return false; 107   return false;
108   } 108   }
109   109  
110   BOOST_FORCEINLINE BOOST_JSON_FASTFLOAT_CONSTEXPR20 110   BOOST_FORCEINLINE BOOST_JSON_FASTFLOAT_CONSTEXPR20
111   bool is_made_of_eight_digits_fast(const char *chars) noexcept { 111   bool is_made_of_eight_digits_fast(const char *chars) noexcept {
HITCBC 112   5367730 return is_made_of_eight_digits_fast(read_u64(chars)); 112   5367730 return is_made_of_eight_digits_fast(read_u64(chars));
113   } 113   }
114   114  
115   template <typename UC> 115   template <typename UC>
116   struct parsed_number_string_t { 116   struct parsed_number_string_t {
117   int64_t exponent{0}; 117   int64_t exponent{0};
118   uint64_t mantissa{0}; 118   uint64_t mantissa{0};
119   UC const * lastmatch{nullptr}; 119   UC const * lastmatch{nullptr};
120   bool negative{false}; 120   bool negative{false};
121   bool valid{false}; 121   bool valid{false};
122   bool too_many_digits{false}; 122   bool too_many_digits{false};
123   // contains the range of the significant digits 123   // contains the range of the significant digits
124   span<const UC> integer{}; // non-nullable 124   span<const UC> integer{}; // non-nullable
125   span<const UC> fraction{}; // nullable 125   span<const UC> fraction{}; // nullable
126   }; 126   };
127   using byte_span = span<char>; 127   using byte_span = span<char>;
128   using parsed_number_string = parsed_number_string_t<char>; 128   using parsed_number_string = parsed_number_string_t<char>;
129   // Assuming that you use no more than 19 digits, this will 129   // Assuming that you use no more than 19 digits, this will
130   // parse an ASCII string. 130   // parse an ASCII string.
131   template <typename UC> 131   template <typename UC>
132   BOOST_FORCEINLINE BOOST_JSON_FASTFLOAT_CONSTEXPR20 132   BOOST_FORCEINLINE BOOST_JSON_FASTFLOAT_CONSTEXPR20
133   parsed_number_string_t<UC> parse_number_string(UC const *p, UC const * pend, parse_options_t<UC> options) noexcept { 133   parsed_number_string_t<UC> parse_number_string(UC const *p, UC const * pend, parse_options_t<UC> options) noexcept {
HITCBC 134   1009310 chars_format const fmt = options.format; 134   1009310 chars_format const fmt = options.format;
HITCBC 135   1009310 UC const decimal_point = options.decimal_point; 135   1009310 UC const decimal_point = options.decimal_point;
136   136  
HITCBC 137   1009310 parsed_number_string_t<UC> answer; 137   1009310 parsed_number_string_t<UC> answer;
HITCBC 138   1009310 answer.valid = false; 138   1009310 answer.valid = false;
HITCBC 139   1009310 answer.too_many_digits = false; 139   1009310 answer.too_many_digits = false;
HITCBC 140   1009310 answer.negative = (*p == UC('-')); 140   1009310 answer.negative = (*p == UC('-'));
HITCBC 141   1009310 if (*p == UC('-')) // C++17 20.19.3.(7.1) explicitly forbids '+' sign here 141   1009310 if (*p == UC('-')) // C++17 20.19.3.(7.1) explicitly forbids '+' sign here
142   { 142   {
HITCBC 143   3902 ++p; 143   3902 ++p;
HITCBC 144   3902 if (p == pend) { 144   3902 if (p == pend) {
MISUBC 145   return answer; 145   return answer;
146   } 146   }
HITCBC 147   7804 if (!is_integer(*p) && (*p != decimal_point)) { // a sign must be followed by an integer or the dot 147   7804 if (!is_integer(*p) && (*p != decimal_point)) { // a sign must be followed by an integer or the dot
MISUBC 148   return answer; 148   return answer;
149   } 149   }
150   } 150   }
HITCBC 151   1009310 UC const * const start_digits = p; 151   1009310 UC const * const start_digits = p;
152   152  
HITCBC 153   1009310 uint64_t i = 0; // an unsigned int avoids signed overflows (which are bad) 153   1009310 uint64_t i = 0; // an unsigned int avoids signed overflows (which are bad)
154   154  
HITCBC 155   40852898 while ((p != pend) && is_integer(*p)) { 155   40852898 while ((p != pend) && is_integer(*p)) {
156   // a multiplication by 10 is cheaper than an arbitrary integer 156   // a multiplication by 10 is cheaper than an arbitrary integer
157   // multiplication 157   // multiplication
HITCBC 158   19417139 i = 10 * i + 158   19417139 i = 10 * i +
HITCBC 159   19417139 uint64_t(*p - UC('0')); // might overflow, we will handle the overflow later 159   19417139 uint64_t(*p - UC('0')); // might overflow, we will handle the overflow later
HITCBC 160   19417139 ++p; 160   19417139 ++p;
161   } 161   }
HITCBC 162   1009310 UC const * const end_of_integer_part = p; 162   1009310 UC const * const end_of_integer_part = p;
HITCBC 163   1009310 int64_t digit_count = int64_t(end_of_integer_part - start_digits); 163   1009310 int64_t digit_count = int64_t(end_of_integer_part - start_digits);
HITCBC 164   1009310 answer.integer = span<const UC>(start_digits, size_t(digit_count)); 164   1009310 answer.integer = span<const UC>(start_digits, size_t(digit_count));
HITCBC 165   1009310 int64_t exponent = 0; 165   1009310 int64_t exponent = 0;
HITCBC 166   1009310 if ((p != pend) && (*p == decimal_point)) { 166   1009310 if ((p != pend) && (*p == decimal_point)) {
HITCBC 167   1006820 ++p; 167   1006820 ++p;
HITCBC 168   1006820 UC const * before = p; 168   1006820 UC const * before = p;
169   // can occur at most twice without overflowing, but let it occur more, since 169   // can occur at most twice without overflowing, but let it occur more, since
170   // for integers with many digits, digit parsing is the primary bottleneck. 170   // for integers with many digits, digit parsing is the primary bottleneck.
171   if (std::is_same<UC,char>::value) { 171   if (std::is_same<UC,char>::value) {
HITCBC 172   6837468 while ((std::distance(p, pend) >= 8) && is_made_of_eight_digits_fast(p)) { 172   6837468 while ((std::distance(p, pend) >= 8) && is_made_of_eight_digits_fast(p)) {
HITCBC 173   2139963 i = i * 100000000 + parse_eight_digits_unrolled(p); // in rare cases, this will overflow, but that's ok 173   2139963 i = i * 100000000 + parse_eight_digits_unrolled(p); // in rare cases, this will overflow, but that's ok
HITCBC 174   2139963 p += 8; 174   2139963 p += 8;
175   } 175   }
176   } 176   }
HITCBC 177   8855670 while ((p != pend) && is_integer(*p)) { 177   8855670 while ((p != pend) && is_integer(*p)) {
HITCBC 178   3423102 uint8_t digit = uint8_t(*p - UC('0')); 178   3423102 uint8_t digit = uint8_t(*p - UC('0'));
HITCBC 179   3423102 ++p; 179   3423102 ++p;
HITCBC 180   3423102 i = i * 10 + digit; // in rare cases, this will overflow, but that's ok 180   3423102 i = i * 10 + digit; // in rare cases, this will overflow, but that's ok
181   } 181   }
HITCBC 182   1006820 exponent = before - p; 182   1006820 exponent = before - p;
HITCBC 183   1006820 answer.fraction = span<const UC>(before, size_t(p - before)); 183   1006820 answer.fraction = span<const UC>(before, size_t(p - before));
HITCBC 184   1006820 digit_count -= exponent; 184   1006820 digit_count -= exponent;
185   } 185   }
186   // we must have encountered at least one integer! 186   // we must have encountered at least one integer!
HITCBC 187   1009310 if (digit_count == 0) { 187   1009310 if (digit_count == 0) {
MISUBC 188   return answer; 188   return answer;
189   } 189   }
HITCBC 190   1009310 int64_t exp_number = 0; // explicit exponential part 190   1009310 int64_t exp_number = 0; // explicit exponential part
HITCBC 191   1009310 if (((unsigned)fmt & (unsigned)chars_format::scientific) && (p != pend) && ((UC('e') == *p) || (UC('E') == *p))) { 191   1009310 if (((unsigned)fmt & (unsigned)chars_format::scientific) && (p != pend) && ((UC('e') == *p) || (UC('E') == *p))) {
HITCBC 192   1005136 UC const * location_of_e = p; 192   1005136 UC const * location_of_e = p;
HITCBC 193   1005136 ++p; 193   1005136 ++p;
HITCBC 194   1005136 bool neg_exp = false; 194   1005136 bool neg_exp = false;
HITCBC 195   1005136 if ((p != pend) && (UC('-') == *p)) { 195   1005136 if ((p != pend) && (UC('-') == *p)) {
HITCBC 196   499687 neg_exp = true; 196   499687 neg_exp = true;
HITCBC 197   499687 ++p; 197   499687 ++p;
HITCBC 198   505449 } else if ((p != pend) && (UC('+') == *p)) { // '+' on exponent is allowed by C++17 20.19.3.(7.1) 198   505449 } else if ((p != pend) && (UC('+') == *p)) { // '+' on exponent is allowed by C++17 20.19.3.(7.1)
MISUBC 199   ++p; 199   ++p;
200   } 200   }
HITCBC 201   2010272 if ((p == pend) || !is_integer(*p)) { 201   2010272 if ((p == pend) || !is_integer(*p)) {
MISUBC 202   if(!((unsigned)fmt & (unsigned)chars_format::fixed)) { 202   if(!((unsigned)fmt & (unsigned)chars_format::fixed)) {
203   // We are in error. 203   // We are in error.
MISUBC 204   return answer; 204   return answer;
205   } 205   }
206   // Otherwise, we will be ignoring the 'e'. 206   // Otherwise, we will be ignoring the 'e'.
MISUBC 207   p = location_of_e; 207   p = location_of_e;
208   } else { 208   } else {
HITCBC 209   7389308 while ((p != pend) && is_integer(*p)) { 209   7389308 while ((p != pend) && is_integer(*p)) {
HITCBC 210   3192086 uint8_t digit = uint8_t(*p - UC('0')); 210   3192086 uint8_t digit = uint8_t(*p - UC('0'));
HITCBC 211   3192086 if (exp_number < 0x10000000) { 211   3192086 if (exp_number < 0x10000000) {
HITCBC 212   3192086 exp_number = 10 * exp_number + digit; 212   3192086 exp_number = 10 * exp_number + digit;
213   } 213   }
HITCBC 214   3192086 ++p; 214   3192086 ++p;
215   } 215   }
HITCBC 216   1005136 if(neg_exp) { exp_number = - exp_number; } 216   1005136 if(neg_exp) { exp_number = - exp_number; }
HITCBC 217   1005136 exponent += exp_number; 217   1005136 exponent += exp_number;
218   } 218   }
HITCBC 219   1005136 } else { 219   1005136 } else {
220   // If it scientific and not fixed, we have to bail out. 220   // If it scientific and not fixed, we have to bail out.
HITCBC 221   4174 if(((unsigned)fmt & (unsigned)chars_format::scientific) && !((unsigned)fmt & (unsigned)chars_format::fixed)) 221   4174 if(((unsigned)fmt & (unsigned)chars_format::scientific) && !((unsigned)fmt & (unsigned)chars_format::fixed))
222   { 222   {
MISUBC 223   return answer; 223   return answer;
224   } 224   }
225   } 225   }
HITCBC 226   1009310 answer.lastmatch = p; 226   1009310 answer.lastmatch = p;
HITCBC 227   1009310 answer.valid = true; 227   1009310 answer.valid = true;
228   228  
229   // If we frequently had to deal with long strings of digits, 229   // If we frequently had to deal with long strings of digits,
230   // we could extend our code by using a 128-bit integer instead 230   // we could extend our code by using a 128-bit integer instead
231   // of a 64-bit integer. However, this is uncommon. 231   // of a 64-bit integer. However, this is uncommon.
232   // 232   //
233   // We can deal with up to 19 digits. 233   // We can deal with up to 19 digits.
HITCBC 234   1009310 if (digit_count > 19) { // this is uncommon 234   1009310 if (digit_count > 19) { // this is uncommon
235   // It is possible that the integer had an overflow. 235   // It is possible that the integer had an overflow.
236   // We have to handle the case where we have 0.0000somenumber. 236   // We have to handle the case where we have 0.0000somenumber.
237   // We need to be mindful of the case where we only have zeroes... 237   // We need to be mindful of the case where we only have zeroes...
238   // E.g., 0.000000000...000. 238   // E.g., 0.000000000...000.
HITCBC 239   1003241 UC const * start = start_digits; 239   1003241 UC const * start = start_digits;
HITCBC 240   2111117 while ((start != pend) && (*start == UC('0') || *start == decimal_point)) { 240   2111117 while ((start != pend) && (*start == UC('0') || *start == decimal_point)) {
HITCBC 241   1107876 if(*start == UC('0')) { digit_count --; } 241   1107876 if(*start == UC('0')) { digit_count --; }
HITCBC 242   1107876 start++; 242   1107876 start++;
243   } 243   }
HITCBC 244   1003241 if (digit_count > 19) { 244   1003241 if (digit_count > 19) {
HITCBC 245   1000712 answer.too_many_digits = true; 245   1000712 answer.too_many_digits = true;
246   // Let us start again, this time, avoiding overflows. 246   // Let us start again, this time, avoiding overflows.
247   // We don't need to check if is_integer, since we use the 247   // We don't need to check if is_integer, since we use the
248   // pre-tokenized spans from above. 248   // pre-tokenized spans from above.
HITCBC 249   1000712 i = 0; 249   1000712 i = 0;
HITCBC 250   1000712 p = answer.integer.ptr; 250   1000712 p = answer.integer.ptr;
HITCBC 251   1000712 UC const * int_end = p + answer.integer.len(); 251   1000712 UC const * int_end = p + answer.integer.len();
HITCBC 252   1000712 constexpr uint64_t minimal_nineteen_digit_integer{1000000000000000000}; 252   1000712 constexpr uint64_t minimal_nineteen_digit_integer{1000000000000000000};
HITCBC 253   19947772 while((i < minimal_nineteen_digit_integer) && (p != int_end)) { 253   19947772 while((i < minimal_nineteen_digit_integer) && (p != int_end)) {
HITCBC 254   18947060 i = i * 10 + uint64_t(*p - UC('0')); 254   18947060 i = i * 10 + uint64_t(*p - UC('0'));
HITCBC 255   18947060 ++p; 255   18947060 ++p;
256   } 256   }
HITCBC 257   1000712 if (i >= minimal_nineteen_digit_integer) { // We have a big integers 257   1000712 if (i >= minimal_nineteen_digit_integer) { // We have a big integers
HITCBC 258   946260 exponent = end_of_integer_part - p + exp_number; 258   946260 exponent = end_of_integer_part - p + exp_number;
259   } else { // We have a value with a fractional component. 259   } else { // We have a value with a fractional component.
HITCBC 260   54452 p = answer.fraction.ptr; 260   54452 p = answer.fraction.ptr;
HITCBC 261   54452 UC const * frac_end = p + answer.fraction.len(); 261   54452 UC const * frac_end = p + answer.fraction.len();
HITCBC 262   121280 while((i < minimal_nineteen_digit_integer) && (p != frac_end)) { 262   121280 while((i < minimal_nineteen_digit_integer) && (p != frac_end)) {
HITCBC 263   66828 i = i * 10 + uint64_t(*p - UC('0')); 263   66828 i = i * 10 + uint64_t(*p - UC('0'));
HITCBC 264   66828 ++p; 264   66828 ++p;
265   } 265   }
HITCBC 266   54452 exponent = answer.fraction.ptr - p + exp_number; 266   54452 exponent = answer.fraction.ptr - p + exp_number;
267   } 267   }
268   // We have now corrected both exponent and i, to a truncated value 268   // We have now corrected both exponent and i, to a truncated value
269   } 269   }
270   } 270   }
HITCBC 271   1009310 answer.exponent = exponent; 271   1009310 answer.exponent = exponent;
HITCBC 272   1009310 answer.mantissa = i; 272   1009310 answer.mantissa = i;
HITCBC 273   1009310 return answer; 273   1009310 return answer;
274   } 274   }
275   275  
276   }}}}}} // namespace s 276   }}}}}} // namespace s
277   277  
278   #endif 278   #endif