/src/jsoncons/include/jsoncons_ext/bson/bson_decimal128.hpp
Line | Count | Source |
1 | | #ifndef JSONCONS_EXT_BSON_BSON_DECIMAL128_HPP |
2 | | #define JSONCONS_EXT_BSON_BSON_DECIMAL128_HPP |
3 | | |
4 | | /* |
5 | | * Implements decimal128_to_chars and decimal128_from_chars |
6 | | * |
7 | | * Based on the libjson functions bson_decimal128_to_string |
8 | | * and bson_decimal128_from_string_w_len, available at |
9 | | * https://github.com/mongodb/mongo-c-driver/blob/master/src/libbson/src/bson/bson-decimal128.h |
10 | | * and https://github.com/mongodb/mongo-c-driver/blob/master/src/libbson/src/bson/bson-decimal128.c |
11 | | * |
12 | | */ |
13 | | |
14 | | /* |
15 | | * Copyright 2015 MongoDB, Inc. |
16 | | * |
17 | | * Licensed under the Apache License, Version 2.0 (the "License"); |
18 | | * you may not use this file except in compliance with the License. |
19 | | * You may obtain a copy of the License at |
20 | | * |
21 | | * http://www.apache.org/licenses/LICENSE-2.0 |
22 | | * |
23 | | * Unless required by applicable law or agreed to in writing, software |
24 | | * distributed under the License is distributed on an "AS IS" BASIS, |
25 | | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
26 | | * See the License for the specific language governing permissions and |
27 | | * limitations under the License. |
28 | | */ |
29 | | |
30 | | #include <algorithm> |
31 | | #include <cstdint> |
32 | | #include <cstring> |
33 | | #include <ctype.h> |
34 | | #include <stdlib.h> |
35 | | #include <cstddef> |
36 | | #include <string.h> |
37 | | #include <string> |
38 | | #include <system_error> |
39 | | #include <type_traits> |
40 | | |
41 | | #include <jsoncons/config/compiler_support.hpp> |
42 | | #include <jsoncons/config/jsoncons_config.hpp> |
43 | | #include <jsoncons/utility/read_number.hpp> |
44 | | #include <jsoncons/utility/write_number.hpp> |
45 | | |
46 | | namespace jsoncons { |
47 | | namespace bson { |
48 | | |
49 | | struct decimal128_to_chars_result |
50 | | { |
51 | | char* ptr; |
52 | | std::errc ec; |
53 | | }; |
54 | | |
55 | | struct decimal128_from_chars_result |
56 | | { |
57 | | const char* ptr; |
58 | | std::errc ec; |
59 | | }; |
60 | | |
61 | | /** |
62 | | * BSON_DECIMAL128_STRING: |
63 | | * |
64 | | * The length of a decimal128 string (with null terminator). |
65 | | * |
66 | | * 1 for the sign |
67 | | * 35 for digits and radix |
68 | | * 2 for exponent indicator and sign |
69 | | * 4 for exponent digits |
70 | | */ |
71 | | #define BSON_DECIMAL128_STRING 43 |
72 | | |
73 | | struct TP1 |
74 | | { |
75 | | uint64_t low; |
76 | | uint64_t high; |
77 | | |
78 | 46.5k | constexpr TP1() : low(0), high(0) {} |
79 | 3.81k | constexpr TP1(uint64_t hi, uint64_t lo) : low(lo), high(hi) {} |
80 | | }; |
81 | | struct TP2 |
82 | | { |
83 | | uint64_t high; |
84 | | uint64_t low; |
85 | | |
86 | 0 | constexpr TP2() : high(0), low(0) {} |
87 | 0 | constexpr TP2(uint64_t hi, uint64_t lo) : high(hi), low(lo) {} |
88 | | }; |
89 | | |
90 | | typedef std::conditional< |
91 | | jsoncons::endian::native == jsoncons::endian::little, |
92 | | TP1, |
93 | | TP2 |
94 | | >::type decimal128_t; |
95 | | |
96 | | inline |
97 | | bool operator==(const decimal128_t& lhs, const decimal128_t& rhs) |
98 | 0 | { |
99 | 0 | return lhs.high == rhs.high && lhs.low == rhs.low; |
100 | 0 | } |
101 | | |
102 | | inline |
103 | | bool operator!=(const decimal128_t& lhs, const decimal128_t& rhs) |
104 | 0 | { |
105 | 0 | return !(lhs == rhs); |
106 | 0 | } |
107 | | |
108 | | struct decimal128_limits |
109 | | { |
110 | | // The length of a decimal128 string (without null terminator). |
111 | | // |
112 | | // 1 for the sign |
113 | | // 35 for digits and radix |
114 | | // 2 for exponent indicator and sign |
115 | | // 4 for exponent digits |
116 | | static constexpr int buf_size = 42; |
117 | | static constexpr int exponent_max = 6111; |
118 | | static constexpr int exponent_min = -6176; |
119 | | static constexpr int exponent_bias = 6176; |
120 | | static constexpr int max_digits = 34; |
121 | | |
122 | 1.80k | static constexpr decimal128_t nan() {return decimal128_t(0x7c00000000000000ull, 0);} |
123 | 204 | static constexpr decimal128_t infinity() {return decimal128_t(0x7800000000000000ull, 0);} |
124 | 1.80k | static constexpr decimal128_t neg_infinity() {return decimal128_t(0x7800000000000000ull + 0x8000000000000000ull, 0);} |
125 | | }; |
126 | | |
127 | | inline |
128 | 0 | bool is_nan(decimal128_t dec) { return dec == decimal128_limits::nan(); } |
129 | | |
130 | | inline |
131 | 0 | bool is_inf(decimal128_t dec) { return dec == decimal128_limits::infinity(); } |
132 | | |
133 | | inline |
134 | 0 | bool is_neg_inf(decimal128_t dec) { return dec == decimal128_limits::neg_infinity(); } |
135 | | |
136 | | /** |
137 | | * bson_uint128_t: |
138 | | * |
139 | | * This struct represents a 128 bit integer. |
140 | | */ |
141 | | typedef struct { |
142 | | uint32_t parts[4]; /* 32-bit words stored high to low. */ |
143 | | } bson_uint128_t; |
144 | | |
145 | | typedef struct { |
146 | | uint64_t high, low; |
147 | | } bson_uint128_6464_t; |
148 | | |
149 | | namespace detail { |
150 | | |
151 | | /** |
152 | | *------------------------------------------------------------------------------ |
153 | | * |
154 | | * bson_uint128_divide1B -- |
155 | | * |
156 | | * This function divides a #bson_uint128_t by 1000000000 (1 billion) and |
157 | | * computes the quotient and remainder. |
158 | | * |
159 | | * The remainder will contain 9 decimal digits for conversion to string. |
160 | | * |
161 | | * @value The #bson_uint128_t operand. |
162 | | * @quotient A pointer to store the #bson_uint128_t quotient. |
163 | | * @rem A pointer to store the #uint64_t remainder. |
164 | | * |
165 | | * Returns: |
166 | | * The quotient at @quotient and the remainder at @rem. |
167 | | * |
168 | | * Side effects: |
169 | | * None. |
170 | | * |
171 | | *------------------------------------------------------------------------------ |
172 | | */ |
173 | | |
174 | | inline |
175 | | void bson_uint128_divide1B (bson_uint128_t value, /* IN */ |
176 | | bson_uint128_t *quotient, /* OUT */ |
177 | | uint32_t *rem) /* OUT */ |
178 | 88.8k | { |
179 | 88.8k | const uint32_t DIVISOR = 1000 * 1000 * 1000; |
180 | 88.8k | uint64_t _rem = 0; |
181 | 88.8k | int i = 0; |
182 | | |
183 | 88.8k | if (!value.parts[0] && !value.parts[1] && !value.parts[2] && |
184 | 32.0k | !value.parts[3]) { |
185 | 8.34k | *quotient = value; |
186 | 8.34k | *rem = 0; |
187 | 8.34k | return; |
188 | 8.34k | } |
189 | | |
190 | 402k | for (i = 0; i <= 3; i++) { |
191 | 322k | _rem <<= 32; /* Adjust remainder to match value of next dividend */ |
192 | 322k | _rem += value.parts[i]; /* Add the divided to _rem */ |
193 | 322k | value.parts[i] = (uint32_t) (_rem / DIVISOR); |
194 | 322k | _rem %= DIVISOR; /* Store the remainder */ |
195 | 322k | } |
196 | | |
197 | 80.5k | *quotient = value; |
198 | 80.5k | *rem = (uint32_t) _rem; |
199 | 80.5k | } |
200 | | |
201 | | /** |
202 | | *------------------------------------------------------------------------- |
203 | | * |
204 | | * mul64x64 -- |
205 | | * |
206 | | * This function multiplies two &uint64_t into a &bson_uint128_6464_t. |
207 | | * |
208 | | * Returns: |
209 | | * The product of @left and @right. |
210 | | * |
211 | | * Side Effects: |
212 | | * None. |
213 | | * |
214 | | *------------------------------------------------------------------------- |
215 | | */ |
216 | | |
217 | | inline |
218 | | void mul_64x64 (uint64_t left, /* IN */ |
219 | | uint64_t right, /* IN */ |
220 | | bson_uint128_6464_t *product) /* OUT */ |
221 | 11.6k | { |
222 | 11.6k | uint64_t left_high, left_low, right_high, right_low, product_high, |
223 | 11.6k | product_mid, product_mid2, product_low; |
224 | 11.6k | bson_uint128_6464_t rt = {0,0}; |
225 | | |
226 | 11.6k | if (!left && !right) { |
227 | 0 | *product = rt; |
228 | 0 | return; |
229 | 0 | } |
230 | | |
231 | 11.6k | left_high = left >> 32; |
232 | 11.6k | left_low = (uint32_t) left; |
233 | 11.6k | right_high = right >> 32; |
234 | 11.6k | right_low = (uint32_t) right; |
235 | | |
236 | 11.6k | product_high = left_high * right_high; |
237 | 11.6k | product_mid = left_high * right_low; |
238 | 11.6k | product_mid2 = left_low * right_high; |
239 | 11.6k | product_low = left_low * right_low; |
240 | | |
241 | 11.6k | product_high += product_mid >> 32; |
242 | 11.6k | product_mid = (uint32_t) product_mid + product_mid2 + (product_low >> 32); |
243 | | |
244 | 11.6k | product_high = product_high + (product_mid >> 32); |
245 | 11.6k | product_low = (product_mid << 32) + (uint32_t) product_low; |
246 | | |
247 | 11.6k | rt.high = product_high; |
248 | 11.6k | rt.low = product_low; |
249 | 11.6k | *product = rt; |
250 | 11.6k | } |
251 | | |
252 | | /** |
253 | | *------------------------------------------------------------------------------ |
254 | | * |
255 | | * dec128_tolower -- |
256 | | * |
257 | | * This function converts the ASCII character @c to lowercase. It is locale |
258 | | * insensitive (unlike the stdlib tolower). |
259 | | * |
260 | | * Returns: |
261 | | * The lowercased character. |
262 | | */ |
263 | | |
264 | | inline |
265 | | char dec128_tolower (char c) |
266 | 54.4k | { |
267 | 54.4k | if (isupper (c)) { |
268 | 8.11k | c += 32; |
269 | 8.11k | } |
270 | | |
271 | 54.4k | return c; |
272 | 54.4k | } |
273 | | |
274 | | /** |
275 | | *------------------------------------------------------------------------------ |
276 | | * |
277 | | * dec128_istreq -- |
278 | | * |
279 | | * This function compares the null-terminated *ASCII* strings @a and @b |
280 | | * for case-insensitive equality. |
281 | | * |
282 | | * Returns: |
283 | | * true if the strings are equal, false otherwise. |
284 | | */ |
285 | | |
286 | | inline |
287 | | bool dec128_istreq (const char* a, const char* lasta, |
288 | | const char* b, const char* lastb) |
289 | 7.08k | { |
290 | 32.2k | while (!(a == lasta && b == lastb)) |
291 | 29.2k | { |
292 | | // strings are different lengths |
293 | 29.2k | if (a == lasta || b == lastb) |
294 | 2.01k | { |
295 | 2.01k | return false; |
296 | 2.01k | } |
297 | | |
298 | 27.2k | if (dec128_tolower (*a) != dec128_tolower (*b)) { |
299 | 2.04k | return false; |
300 | 2.04k | } |
301 | | |
302 | 25.2k | a++; |
303 | 25.2k | b++; |
304 | 25.2k | } |
305 | | |
306 | 3.03k | return true; |
307 | 7.08k | } |
308 | | |
309 | | } // namespace detail |
310 | | |
311 | | |
312 | | /** |
313 | | *------------------------------------------------------------------------------ |
314 | | * |
315 | | * decimal128_to_chars -- |
316 | | * |
317 | | * This function converts a BID formatted decimal128 value to string, |
318 | | * accepting a &decimal128_t as @dec. The string is stored at @str. |
319 | | * |
320 | | * @dec : The BID formatted decimal to convert. |
321 | | * @str : The output decimal128 string. At least %BSON_DECIMAL128_STRING |
322 | | *characters. |
323 | | * |
324 | | * Returns: |
325 | | * None. |
326 | | * |
327 | | * Side effects: |
328 | | * None. |
329 | | * |
330 | | *------------------------------------------------------------------------------ |
331 | | */ |
332 | | |
333 | | inline |
334 | | decimal128_to_chars_result decimal128_to_chars(char* first, char* last, const decimal128_t& dec) |
335 | 31.0k | { |
336 | 31.0k | const std::string bson_decimal128_inf = "Infinity"; |
337 | 31.0k | const std::string bson_decimal128_nan = "NaN"; |
338 | | |
339 | 31.0k | const uint32_t combination_mask = 0x1f; /* Extract least significant 5 bits */ |
340 | 31.0k | const uint32_t exponent_mask = 0x3fff; /* Extract least significant 14 bits */ |
341 | 31.0k | const uint32_t combination_infinity = 30; /* Value of combination field for Inf */ |
342 | 31.0k | const uint32_t combination_nan = 31; /* Value of combination field for NaN */ |
343 | 31.0k | const uint32_t exponent_bias = 6176; /* decimal128 exponent bias */ |
344 | | |
345 | 31.0k | char* str_out = first; /* output pointer in string */ |
346 | 31.0k | char significand_str[35]; /* decoded significand digits */ |
347 | | |
348 | | /* Note: bits in this routine are referred to starting at 0, */ |
349 | | /* from the sign bit, towards the coefficient. */ |
350 | 31.0k | uint32_t high; /* bits 0 - 31 */ |
351 | 31.0k | uint32_t midh; /* bits 32 - 63 */ |
352 | 31.0k | uint32_t midl; /* bits 64 - 95 */ |
353 | 31.0k | uint32_t low; /* bits 96 - 127 */ |
354 | 31.0k | uint32_t combination; /* bits 1 - 5 */ |
355 | 31.0k | uint32_t biased_exponent; /* decoded biased exponent (14 bits) */ |
356 | 31.0k | uint32_t significand_digits = 0; /* the number of significand digits */ |
357 | 31.0k | uint32_t significand[36] = {0}; /* the base-10 digits in the significand */ |
358 | 31.0k | uint32_t *significand_read = significand; /* read pointer into significand */ |
359 | 31.0k | int32_t exponent; /* unbiased exponent */ |
360 | 31.0k | int32_t scientific_exponent; /* the exponent if scientific notation is |
361 | | * used */ |
362 | 31.0k | bool is_zero = false; /* true if the number is zero */ |
363 | | |
364 | 31.0k | uint8_t significand_msb; /* the most signifcant significand bits (50-46) */ |
365 | 31.0k | bson_uint128_t |
366 | 31.0k | significand128; /* temporary storage for significand decoding */ |
367 | | |
368 | 31.0k | memset (significand_str, 0, sizeof (significand_str)); |
369 | | |
370 | 31.0k | if ((int64_t) dec.high < 0) { /* negative */ |
371 | 7.97k | *(str_out++) = '-'; |
372 | 7.97k | } |
373 | | |
374 | 31.0k | low = (uint32_t) dec.low, midl = (uint32_t) (dec.low >> 32), |
375 | 31.0k | midh = (uint32_t) dec.high, high = (uint32_t) (dec.high >> 32); |
376 | | |
377 | | /* Decode combination field and exponent */ |
378 | 31.0k | combination = (high >> 26) & combination_mask; |
379 | | |
380 | 31.0k | if (JSONCONS_UNLIKELY ((combination >> 3) == 3)) { |
381 | | /* Check for 'special' values */ |
382 | 7.77k | if (combination == combination_infinity) { /* Infinity */ |
383 | 2.56k | if (last-str_out >= static_cast<ptrdiff_t >(bson_decimal128_inf.size())) |
384 | 2.56k | { |
385 | 2.56k | std::memcpy(str_out, bson_decimal128_inf.data(), bson_decimal128_inf.size()); |
386 | 2.56k | str_out += bson_decimal128_inf.size(); |
387 | 2.56k | } |
388 | 2.56k | *str_out = 0; |
389 | | //strcpy_s (str_out, last-str_out, bson_decimal128_inf.c_str()); |
390 | 2.56k | return decimal128_to_chars_result{str_out, std::errc{}}; |
391 | 5.20k | } else if (combination == combination_nan) { /* NaN */ |
392 | | /* first, not str_out, to erase the sign */ |
393 | 2.43k | str_out = first; |
394 | 2.43k | if (last-str_out >= static_cast<ptrdiff_t >(bson_decimal128_nan.size())) |
395 | 2.43k | { |
396 | 2.43k | std::memcpy(str_out, bson_decimal128_nan.data(), bson_decimal128_nan.size()); |
397 | 2.43k | str_out += bson_decimal128_nan.size(); |
398 | 2.43k | } |
399 | 2.43k | *str_out = 0; |
400 | | //strcpy_s (first, last-first, bson_decimal128_nan.c_str()); |
401 | | /* we don't care about the NaN payload. */ |
402 | 2.43k | return decimal128_to_chars_result{str_out, std::errc{}}; |
403 | 2.77k | } else { |
404 | 2.77k | biased_exponent = (high >> 15) & exponent_mask; |
405 | 2.77k | significand_msb = 0x8 + ((high >> 14) & 0x1); |
406 | 2.77k | } |
407 | 23.3k | } else { |
408 | 23.3k | significand_msb = (high >> 14) & 0x7; |
409 | 23.3k | biased_exponent = (high >> 17) & exponent_mask; |
410 | 23.3k | } |
411 | | |
412 | 26.0k | exponent = biased_exponent - exponent_bias; |
413 | | /* Create string of significand digits */ |
414 | | |
415 | | /* Convert the 114-bit binary number represented by */ |
416 | | /* (high, midh, midl, low) to at most 34 decimal */ |
417 | | /* digits through modulo and division. */ |
418 | 26.0k | significand128.parts[0] = (high & 0x3fff) + ((significand_msb & 0xf) << 14); |
419 | 26.0k | significand128.parts[1] = midh; |
420 | 26.0k | significand128.parts[2] = midl; |
421 | 26.0k | significand128.parts[3] = low; |
422 | | |
423 | 26.0k | if (significand128.parts[0] == 0 && significand128.parts[1] == 0 && |
424 | 4.76k | significand128.parts[2] == 0 && significand128.parts[3] == 0) { |
425 | 1.09k | is_zero = true; |
426 | 24.9k | } else if (significand128.parts[0] >= (1 << 17)) { |
427 | | /* The significand is non-canonical or zero. |
428 | | * In order to preserve compatibility with the densely packed decimal |
429 | | * format, the maximum value for the significand of decimal128 is |
430 | | * 1e34 - 1. If the value is greater than 1e34 - 1, the IEEE 754 |
431 | | * standard dictates that the significand is interpreted as zero. |
432 | | */ |
433 | 2.77k | is_zero = true; |
434 | 22.2k | } else { |
435 | 111k | for (int k = 3; k >= 0; k--) { |
436 | 88.8k | uint32_t least_digits = 0; |
437 | 88.8k | detail::bson_uint128_divide1B ( |
438 | 88.8k | significand128, &significand128, &least_digits); |
439 | | |
440 | | /* We now have the 9 least significant digits (in base 2). */ |
441 | | /* Convert and output to string. */ |
442 | 88.8k | if (!least_digits) { |
443 | 8.35k | continue; |
444 | 8.35k | } |
445 | | |
446 | 805k | for (int j = 8; j >= 0; j--) { |
447 | 724k | significand[k * 9 + j] = least_digits % 10; |
448 | 724k | least_digits /= 10; |
449 | 724k | } |
450 | 80.5k | } |
451 | 22.2k | } |
452 | | |
453 | | /* Output format options: */ |
454 | | /* Scientific - [-]d.dddE(+/-)dd or [-]dE(+/-)dd */ |
455 | | /* Regular - ddd.ddd */ |
456 | | |
457 | 26.0k | if (is_zero) { |
458 | 3.86k | significand_digits = 1; |
459 | 3.86k | *significand_read = 0; |
460 | 22.2k | } else { |
461 | 22.2k | significand_digits = 36; |
462 | 175k | while (!(*significand_read)) { |
463 | 153k | significand_digits--; |
464 | 153k | significand_read++; |
465 | 153k | } |
466 | 22.2k | } |
467 | | |
468 | 26.0k | scientific_exponent = significand_digits - 1 + exponent; |
469 | | |
470 | | /* The scientific exponent checks are dictated by the string conversion |
471 | | * specification and are somewhat arbitrary cutoffs. |
472 | | * |
473 | | * We must check exponent > 0, because if this is the case, the number |
474 | | * has trailing zeros. However, we *cannot* output these trailing zeros, |
475 | | * because doing so would change the precision of the value, and would |
476 | | * change stored data if the string converted number is round tripped. |
477 | | */ |
478 | 26.0k | if (scientific_exponent < -6 || exponent > 0) { |
479 | | /* Scientific format */ |
480 | 21.2k | *(str_out++) = char(*(significand_read++)) + '0'; |
481 | 21.2k | significand_digits--; |
482 | | |
483 | 21.2k | if (significand_digits) { |
484 | 18.3k | *(str_out++) = '.'; |
485 | 18.3k | } |
486 | | |
487 | 544k | for (std::size_t i = 0; i < significand_digits && (str_out - first) < 36; i++) { |
488 | 523k | *(str_out++) = char(*(significand_read++)) + '0'; |
489 | 523k | } |
490 | | /* Exponent */ |
491 | 21.2k | *(str_out++) = 'E'; |
492 | | |
493 | 21.2k | std::string s; |
494 | 21.2k | if (scientific_exponent >= 0) { |
495 | 5.61k | s.push_back('+'); |
496 | 5.61k | } |
497 | 21.2k | jsoncons::utility::from_integer(scientific_exponent, s); |
498 | 21.2k | if (str_out + s.size() < last) |
499 | 19.8k | { |
500 | 19.8k | std::memcpy(str_out, s.data(), s.size()); |
501 | 19.8k | } |
502 | 1.39k | else |
503 | 1.39k | { |
504 | 1.39k | return decimal128_to_chars_result{str_out, std::errc::value_too_large}; |
505 | 1.39k | } |
506 | 19.8k | str_out += s.size(); |
507 | 19.8k | } else { |
508 | | /* Regular format with no decimal place */ |
509 | 4.85k | if (exponent >= 0) { |
510 | 19.4k | for (std::size_t i = 0; i < significand_digits && (str_out - first) < 36; i++) { |
511 | 17.5k | *(str_out++) = char(*(significand_read++)) + '0'; |
512 | 17.5k | } |
513 | 2.95k | } else { |
514 | 2.95k | int32_t radix_position = significand_digits + exponent; |
515 | | |
516 | 2.95k | if (radix_position > 0) { /* non-zero digits before radix */ |
517 | 959 | for (int32_t i = 0; |
518 | 7.30k | i < radix_position && (str_out < last); |
519 | 6.34k | i++) { |
520 | 6.34k | *(str_out++) = char(*(significand_read++)) + '0'; |
521 | 6.34k | } |
522 | 1.99k | } else { /* leading zero before radix point */ |
523 | 1.99k | *(str_out++) = '0'; |
524 | 1.99k | } |
525 | | |
526 | 2.95k | *(str_out++) = '.'; |
527 | 8.26k | while (radix_position++ < 0) { /* add leading zeros after radix */ |
528 | 5.31k | *(str_out++) = '0'; |
529 | 5.31k | } |
530 | | |
531 | 2.95k | for (std::size_t i = 0; |
532 | 84.4k | (i < significand_digits - (std::max) (radix_position - 1, 0)) && |
533 | 81.4k | (str_out < last); |
534 | 81.4k | i++) { |
535 | 81.4k | *(str_out++) = char(*(significand_read++)) + '0'; |
536 | 81.4k | } |
537 | 2.95k | } |
538 | 4.85k | } |
539 | 24.6k | return decimal128_to_chars_result{str_out, std::errc{}}; |
540 | 26.0k | } |
541 | | |
542 | | |
543 | | |
544 | | /** |
545 | | *------------------------------------------------------------------------------ |
546 | | * |
547 | | * bson_decimal128_from_string_w_len -- |
548 | | * |
549 | | * This function converts @string in the format [+-]ddd[.]ddd[E][+-]dddd to |
550 | | * decimal128. Out of range values are converted to +/-Infinity. Invalid |
551 | | * strings are converted to NaN. @len is the length of the string, or -1 |
552 | | * meaning the string is null-terminated. |
553 | | * |
554 | | * If more digits are provided than the available precision allows, |
555 | | * round to the nearest expressable decimal128 with ties going to even will |
556 | | * occur. |
557 | | * |
558 | | * Note: @string must be ASCII only! |
559 | | * |
560 | | * Returns: |
561 | | * true on success, or false on failure. @dec will be NaN if @str was invalid |
562 | | * The &decimal128_t converted from @string at @dec. |
563 | | * |
564 | | * Side effects: |
565 | | * None. |
566 | | * |
567 | | *------------------------------------------------------------------------------ |
568 | | */ |
569 | | |
570 | | inline |
571 | | decimal128_from_chars_result decimal128_from_chars(const char* first, const char* last, decimal128_t& dec) |
572 | 15.4k | { |
573 | 15.4k | const string_view inf_str = "inf"; |
574 | 15.4k | const string_view infinity_str = "infinity"; |
575 | 15.4k | const string_view nan_str = "nan"; |
576 | | |
577 | 15.4k | ptrdiff_t len = last - first; |
578 | | |
579 | 15.4k | bson_uint128_6464_t significand = {0,0}; |
580 | | |
581 | 15.4k | const char* str_read = first; /* Read pointer for consuming str. */ |
582 | | |
583 | | /* Parsing state tracking */ |
584 | 15.4k | bool is_negative = false; |
585 | 15.4k | bool saw_radix = false; |
586 | 15.4k | bool includes_sign = false; /* True if the input first contains a sign. */ |
587 | 15.4k | bool found_nonzero = false; |
588 | | |
589 | 15.4k | std::size_t significant_digits = 0; /* Total number of significant digits |
590 | | * (no leading or trailing zero) */ |
591 | 15.4k | std::size_t ndigits_read = 0; /* Total number of significand digits read */ |
592 | 15.4k | std::size_t ndigits = 0; /* Total number of digits (no leading zeros) */ |
593 | 15.4k | std::size_t radix_position = 0; /* The number of the digits after radix */ |
594 | 15.4k | std::size_t first_nonzero = 0; /* The index of the first non-zero in *str* */ |
595 | | |
596 | 15.4k | uint16_t digits[decimal128_limits::max_digits] = {0}; |
597 | 15.4k | uint16_t ndigits_stored = 0; /* The number of digits in digits */ |
598 | 15.4k | uint16_t *digits_insert = digits; /* Insertion pointer for digits */ |
599 | 15.4k | std::size_t first_digit = 0; /* The index of the first non-zero digit */ |
600 | 15.4k | std::size_t last_digit = 0; /* The index of the last digit */ |
601 | | |
602 | 15.4k | int32_t exponent = 0; |
603 | 15.4k | uint64_t significand_high = 0; /* The high 17 digits of the significand */ |
604 | 15.4k | uint64_t significand_low = 0; /* The low 17 digits of the significand */ |
605 | 15.4k | uint16_t biased_exponent = 0; /* The biased exponent */ |
606 | | |
607 | 15.4k | dec.high = 0; |
608 | 15.4k | dec.low = 0; |
609 | | |
610 | 15.4k | if (*str_read == '+' || *str_read == '-') { |
611 | 3.56k | is_negative = *(str_read++) == '-'; |
612 | 3.56k | includes_sign = true; |
613 | 3.56k | } |
614 | | |
615 | | /* Check for Infinity or NaN */ |
616 | 15.4k | if (!isdigit(*str_read) && *str_read != '.') { |
617 | 3.03k | if (detail::dec128_istreq (str_read, last, inf_str.data(), inf_str.data()+inf_str.length()) || |
618 | 3.03k | detail::dec128_istreq (str_read, last, infinity_str.data(), infinity_str.data()+infinity_str.length())) |
619 | 2.01k | { |
620 | 2.01k | dec = is_negative ? decimal128_limits::neg_infinity() : decimal128_limits::infinity(); |
621 | 2.01k | return decimal128_from_chars_result{str_read,std::errc{}}; |
622 | 2.01k | } else if (detail::dec128_istreq (str_read, last, nan_str.data(), nan_str.data()+nan_str.length())) { |
623 | 1.02k | dec = decimal128_limits::nan(); |
624 | 1.02k | return decimal128_from_chars_result{str_read,std::errc{}}; |
625 | 1.02k | } |
626 | | |
627 | 0 | dec = decimal128_limits::nan(); |
628 | 0 | return decimal128_from_chars_result{str_read,std::errc::invalid_argument}; |
629 | 3.03k | } |
630 | | |
631 | | /* Read digits */ |
632 | 340k | while (((isdigit (*str_read) || *str_read == '.')) && |
633 | 328k | (len == -1 || str_read < first + len)) { |
634 | 328k | if (*str_read == '.') { |
635 | 10.2k | if (saw_radix) { |
636 | 0 | dec = decimal128_limits::nan(); |
637 | 0 | return decimal128_from_chars_result{str_read,std::errc::invalid_argument}; |
638 | 0 | } |
639 | | |
640 | 10.2k | saw_radix = true; |
641 | 10.2k | str_read++; |
642 | 10.2k | continue; |
643 | 10.2k | } |
644 | | |
645 | 317k | if (ndigits_stored < 34) { |
646 | 316k | if (*str_read != '0' || found_nonzero) { |
647 | 311k | if (!found_nonzero) { |
648 | 10.7k | first_nonzero = ndigits_read; |
649 | 10.7k | } |
650 | | |
651 | 311k | found_nonzero = true; |
652 | 311k | *(digits_insert++) = *(str_read) - '0'; /* Only store 34 digits */ |
653 | 311k | ndigits_stored++; |
654 | 311k | } |
655 | 316k | } |
656 | | |
657 | 317k | if (found_nonzero) { |
658 | 313k | ndigits++; |
659 | 313k | } |
660 | | |
661 | 317k | if (saw_radix) { |
662 | 298k | radix_position++; |
663 | 298k | } |
664 | | |
665 | 317k | ndigits_read++; |
666 | 317k | str_read++; |
667 | 317k | } |
668 | | |
669 | 12.4k | if (saw_radix && !ndigits_read) { |
670 | 0 | dec = decimal128_limits::nan(); |
671 | 0 | return decimal128_from_chars_result{str_read,std::errc::invalid_argument}; |
672 | 0 | } |
673 | | |
674 | | /* Read exponent if exists */ |
675 | 12.4k | if (*str_read == 'e' || *str_read == 'E') { |
676 | 10.1k | ++str_read; |
677 | 10.1k | if (*str_read == '+') { |
678 | 3.09k | ++str_read; |
679 | 3.09k | } |
680 | 10.1k | auto result = jsoncons::utility::to_integer(str_read, last - str_read, exponent); |
681 | 10.1k | if (result.ec != std::errc{}) |
682 | 260 | { |
683 | 260 | dec = decimal128_limits::nan(); |
684 | 260 | return decimal128_from_chars_result{str_read,std::errc::invalid_argument}; |
685 | 260 | } |
686 | 9.90k | str_read = result.ptr; |
687 | 9.90k | } |
688 | | |
689 | 12.1k | if ((len == -1 || str_read < first + len) && *str_read) { |
690 | 0 | dec = decimal128_limits::nan(); |
691 | 0 | return decimal128_from_chars_result{str_read,std::errc::invalid_argument}; |
692 | 0 | } |
693 | | |
694 | | /* Done reading input. */ |
695 | | /* Find first non-zero digit in digits */ |
696 | 12.1k | first_digit = 0; |
697 | | |
698 | 12.1k | if (!ndigits_stored) { /* value is zero */ |
699 | 1.71k | first_digit = 0; |
700 | 1.71k | last_digit = 0; |
701 | 1.71k | digits[0] = 0; |
702 | 1.71k | ndigits = 1; |
703 | 1.71k | ndigits_stored = 1; |
704 | 1.71k | significant_digits = 0; |
705 | 10.4k | } else { |
706 | 10.4k | last_digit = ndigits_stored - 1; |
707 | 10.4k | significant_digits = ndigits; |
708 | | /* Mark trailing zeros as non-significant */ |
709 | 12.9k | while (first[first_nonzero + significant_digits - 1 + includes_sign + |
710 | 12.9k | saw_radix] == '0') { |
711 | 2.44k | significant_digits--; |
712 | 2.44k | } |
713 | 10.4k | } |
714 | | |
715 | | |
716 | | /* Normalization of exponent */ |
717 | | /* Correct exponent based on radix position, and shift significand as needed |
718 | | */ |
719 | | /* to represent user input */ |
720 | | |
721 | | /* Overflow prevention */ |
722 | 12.1k | if (exponent <= static_cast<int32_t>(radix_position) && static_cast<int32_t>(radix_position) - exponent > (1 << 14)) { |
723 | 0 | exponent = decimal128_limits::exponent_min; |
724 | 12.1k | } else { |
725 | 12.1k | exponent -= static_cast<int32_t>(radix_position); |
726 | 12.1k | } |
727 | | |
728 | | /* Attempt to normalize the exponent */ |
729 | 12.1k | while (exponent > decimal128_limits::exponent_max) { |
730 | | /* Shift exponent to significand and decrease */ |
731 | 0 | last_digit++; |
732 | | |
733 | 0 | if (last_digit - first_digit > decimal128_limits::max_digits) { |
734 | | /* The exponent is too great to shift into the significand. */ |
735 | 0 | if (significant_digits == 0) { |
736 | | /* Value is zero, we are allowed to clamp the exponent. */ |
737 | 0 | exponent = decimal128_limits::exponent_max; |
738 | 0 | break; |
739 | 0 | } |
740 | | |
741 | | /* Overflow is not permitted, error. */ |
742 | 0 | dec = decimal128_limits::nan(); |
743 | 0 | return decimal128_from_chars_result{str_read,std::errc::invalid_argument}; |
744 | 0 | } |
745 | | |
746 | 0 | exponent--; |
747 | 0 | } |
748 | | |
749 | 13.0k | while (exponent < decimal128_limits::exponent_min || ndigits_stored < ndigits) { |
750 | | /* Shift last digit */ |
751 | 1.13k | if (last_digit == 0) { |
752 | | /* underflow is not allowed, but zero clamping is */ |
753 | 0 | if (significant_digits == 0) { |
754 | 0 | exponent = decimal128_limits::exponent_min; |
755 | 0 | break; |
756 | 0 | } |
757 | | |
758 | 0 | dec = decimal128_limits::nan(); |
759 | 0 | return decimal128_from_chars_result{str_read,std::errc::invalid_argument}; |
760 | 0 | } |
761 | | |
762 | 1.13k | if (ndigits_stored < ndigits) { |
763 | 1.13k | if (first[ndigits - 1 + includes_sign + saw_radix] - '0' != 0 && |
764 | 295 | significant_digits != 0) { |
765 | 295 | dec = decimal128_limits::nan(); |
766 | 295 | return decimal128_from_chars_result{str_read,std::errc::invalid_argument}; |
767 | 295 | } |
768 | | |
769 | 839 | ndigits--; /* adjust to match digits not stored */ |
770 | 839 | } else { |
771 | 0 | if (digits[last_digit] != 0) { |
772 | | /* Inexact rounding is not allowed. */ |
773 | 0 | dec = decimal128_limits::nan(); |
774 | 0 | return decimal128_from_chars_result{str_read,std::errc::invalid_argument}; |
775 | 0 | } |
776 | | |
777 | | |
778 | 0 | last_digit--; /* adjust to round */ |
779 | 0 | } |
780 | | |
781 | 839 | if (exponent < decimal128_limits::exponent_max) { |
782 | 839 | exponent++; |
783 | 839 | } else { |
784 | 0 | dec = decimal128_limits::nan(); |
785 | 0 | return decimal128_from_chars_result{str_read,std::errc::invalid_argument}; |
786 | 0 | } |
787 | 839 | } |
788 | | |
789 | | /* Round */ |
790 | | /* We've normalized the exponent, but might still need to round. */ |
791 | 11.8k | if (last_digit - first_digit + 1 < significant_digits) { |
792 | 230 | uint8_t round_digit; |
793 | | |
794 | | /* There are non-zero digits after last_digit that need rounding. */ |
795 | | /* We round to nearest, ties to even */ |
796 | 230 | round_digit = |
797 | 230 | first[first_nonzero + last_digit + includes_sign + saw_radix + 1] - |
798 | 230 | '0'; |
799 | | |
800 | 230 | if (round_digit != 0) { |
801 | | /* Inexact (non-zero) rounding is not allowed */ |
802 | 230 | dec = decimal128_limits::nan(); |
803 | 230 | return decimal128_from_chars_result{str_read,std::errc::invalid_argument}; |
804 | 230 | } |
805 | 230 | } |
806 | | |
807 | | /* Encode significand */ |
808 | 11.6k | significand_high = 0, /* The high 17 digits of the significand */ |
809 | 11.6k | significand_low = 0; /* The low 17 digits of the significand */ |
810 | | |
811 | 11.6k | if (significant_digits == 0) { /* read a zero */ |
812 | 1.71k | significand_high = 0; |
813 | 1.71k | significand_low = 0; |
814 | 9.95k | } else if (last_digit - first_digit < 17) { |
815 | 1.04k | std::size_t d_idx = first_digit; |
816 | 1.04k | significand_low = digits[d_idx++]; |
817 | | |
818 | 7.72k | for (; d_idx <= last_digit; d_idx++) { |
819 | 6.68k | significand_low *= 10; |
820 | 6.68k | significand_low += digits[d_idx]; |
821 | 6.68k | significand_high = 0; |
822 | 6.68k | } |
823 | 8.91k | } else { |
824 | 8.91k | std::size_t d_idx = first_digit; |
825 | 8.91k | significand_high = digits[d_idx++]; |
826 | | |
827 | 126k | for (; d_idx <= last_digit - 17; d_idx++) { |
828 | 117k | significand_high *= 10; |
829 | 117k | significand_high += digits[d_idx]; |
830 | 117k | } |
831 | | |
832 | 8.91k | significand_low = digits[d_idx++]; |
833 | | |
834 | 151k | for (; d_idx <= last_digit; d_idx++) { |
835 | 142k | significand_low *= 10; |
836 | 142k | significand_low += digits[d_idx]; |
837 | 142k | } |
838 | 8.91k | } |
839 | | |
840 | 11.6k | detail::mul_64x64 (significand_high, 100000000000000000ull, &significand); |
841 | 11.6k | significand.low += significand_low; |
842 | | |
843 | 11.6k | if (significand.low < significand_low) { |
844 | 1.97k | significand.high += 1; |
845 | 1.97k | } |
846 | | |
847 | | |
848 | 11.6k | biased_exponent = static_cast<uint16_t>(exponent + static_cast<int32_t>(decimal128_limits::exponent_bias)); |
849 | | |
850 | | /* Encode combination, exponent, and significand. */ |
851 | 11.6k | if ((significand.high >> 49) & 1) { |
852 | | /* Encode '11' into bits 1 to 3 */ |
853 | 0 | dec.high |= (0x3ull << 61); |
854 | 0 | dec.high |= (biased_exponent & 0x3fffull) << 47; |
855 | 0 | dec.high |= significand.high & 0x7fffffffffffull; |
856 | 11.6k | } else { |
857 | 11.6k | dec.high |= (biased_exponent & 0x3fffull) << 49; |
858 | 11.6k | dec.high |= significand.high & 0x1ffffffffffffull; |
859 | 11.6k | } |
860 | | |
861 | 11.6k | dec.low = significand.low; |
862 | | |
863 | | /* Encode sign */ |
864 | 11.6k | if (is_negative) { |
865 | 1.45k | dec.high |= 0x8000000000000000ull; |
866 | 1.45k | } |
867 | | |
868 | 11.6k | return decimal128_from_chars_result{str_read,std::errc{}}; |
869 | 11.8k | } |
870 | | |
871 | | } // namespace bson |
872 | | } // namespace jsoncons |
873 | | |
874 | | #endif // JSONCONS_EXT_BSON_BSON_DECIMAL128_HPP |