aboutsummaryrefslogtreecommitdiff
path: root/include/jsoncons_ext/bson/bson_decimal128.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'include/jsoncons_ext/bson/bson_decimal128.hpp')
-rw-r--r--include/jsoncons_ext/bson/bson_decimal128.hpp865
1 files changed, 865 insertions, 0 deletions
diff --git a/include/jsoncons_ext/bson/bson_decimal128.hpp b/include/jsoncons_ext/bson/bson_decimal128.hpp
new file mode 100644
index 0000000..b487a04
--- /dev/null
+++ b/include/jsoncons_ext/bson/bson_decimal128.hpp
@@ -0,0 +1,865 @@
+#ifndef JSONCONS_BSON_BSON_DECIMAL128_HPP
+#define JSONCONS_BSON_BSON_DECIMAL128_HPP
+
+/*
+ * Implements decimal128_to_chars and decimal128_from_chars
+ *
+ * Based on the libjson functions bson_decimal128_to_string
+ * and bson_decimal128_from_string_w_len, available at
+ * https://github.com/mongodb/mongo-c-driver/blob/master/src/libbson/src/bson/bson-decimal128.h
+ * and https://github.com/mongodb/mongo-c-driver/blob/master/src/libbson/src/bson/bson-decimal128.c
+ *
+*/
+
+/*
+ * Copyright 2015 MongoDB, Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <cstring>
+#include <ctype.h>
+#include <system_error>
+#include <algorithm>
+#include <jsoncons/config/jsoncons_config.hpp>
+
+namespace jsoncons { namespace bson {
+
+ struct decimal128_to_chars_result
+ {
+ char* ptr;
+ std::errc ec;
+ };
+
+ struct decimal128_from_chars_result
+ {
+ const char* ptr;
+ std::errc ec;
+ };
+
+/**
+ * BSON_DECIMAL128_STRING:
+ *
+ * The length of a decimal128 string (with null terminator).
+ *
+ * 1 for the sign
+ * 35 for digits and radix
+ * 2 for exponent indicator and sign
+ * 4 for exponent digits
+ */
+#define BSON_DECIMAL128_STRING 43
+
+ struct TP1
+ {
+ uint64_t low;
+ uint64_t high;
+
+ constexpr TP1() : low(0), high(0) {}
+ constexpr TP1(uint64_t hi, uint64_t lo) : low(lo), high(hi) {}
+ };
+ struct TP2
+ {
+ uint64_t high;
+ uint64_t low;
+
+ constexpr TP2() : high(0), low(0) {}
+ constexpr TP2(uint64_t hi, uint64_t lo) : high(hi), low(lo) {}
+ };
+
+ typedef std::conditional<
+ jsoncons::endian::native == jsoncons::endian::little,
+ TP1,
+ TP2
+ >::type decimal128_t;
+
+ inline
+ bool operator==(const decimal128_t& lhs, const decimal128_t& rhs)
+ {
+ return lhs.high == rhs.high && lhs.low == rhs.low;
+ }
+
+ inline
+ bool operator!=(const decimal128_t& lhs, const decimal128_t& rhs)
+ {
+ return !(lhs == rhs);
+ }
+
+ struct decimal128_limits
+ {
+ // The length of a decimal128 string (without null terminator).
+ //
+ // 1 for the sign
+ // 35 for digits and radix
+ // 2 for exponent indicator and sign
+ // 4 for exponent digits
+ static constexpr int buf_size = 42;
+ static constexpr int exponent_max = 6111;
+ static constexpr int exponent_min = -6176;
+ static constexpr int exponent_bias = 6176;
+ static constexpr int max_digits = 34;
+
+ static constexpr decimal128_t nan() {return decimal128_t(0x7c00000000000000ull, 0);}
+ static constexpr decimal128_t infinity() {return decimal128_t(0x7800000000000000ull, 0);}
+ static constexpr decimal128_t neg_infinity() {return decimal128_t(0x7800000000000000ull + 0x8000000000000000ull, 0);}
+ };
+
+ inline
+ bool is_nan(decimal128_t dec) { return dec == decimal128_limits::nan(); }
+
+ inline
+ bool is_inf(decimal128_t dec) { return dec == decimal128_limits::infinity(); }
+
+ inline
+ bool is_neg_inf(decimal128_t dec) { return dec == decimal128_limits::neg_infinity(); }
+
+ /**
+ * bson_uint128_t:
+ *
+ * This struct represents a 128 bit integer.
+ */
+ typedef struct {
+ uint32_t parts[4]; /* 32-bit words stored high to low. */
+ } bson_uint128_t;
+
+ typedef struct {
+ uint64_t high, low;
+ } bson_uint128_6464_t;
+
+ namespace detail {
+
+ /**
+ *------------------------------------------------------------------------------
+ *
+ * bson_uint128_divide1B --
+ *
+ * This function divides a #bson_uint128_t by 1000000000 (1 billion) and
+ * computes the quotient and remainder.
+ *
+ * The remainder will contain 9 decimal digits for conversion to string.
+ *
+ * @value The #bson_uint128_t operand.
+ * @quotient A pointer to store the #bson_uint128_t quotient.
+ * @rem A pointer to store the #uint64_t remainder.
+ *
+ * Returns:
+ * The quotient at @quotient and the remainder at @rem.
+ *
+ * Side effects:
+ * None.
+ *
+ *------------------------------------------------------------------------------
+ */
+
+ inline
+ void bson_uint128_divide1B (bson_uint128_t value, /* IN */
+ bson_uint128_t *quotient, /* OUT */
+ uint32_t *rem) /* OUT */
+ {
+ const uint32_t DIVISOR = 1000 * 1000 * 1000;
+ uint64_t _rem = 0;
+ int i = 0;
+
+ if (!value.parts[0] && !value.parts[1] && !value.parts[2] &&
+ !value.parts[3]) {
+ *quotient = value;
+ *rem = 0;
+ return;
+ }
+
+ for (i = 0; i <= 3; i++) {
+ _rem <<= 32; /* Adjust remainder to match value of next dividend */
+ _rem += value.parts[i]; /* Add the divided to _rem */
+ value.parts[i] = (uint32_t) (_rem / DIVISOR);
+ _rem %= DIVISOR; /* Store the remainder */
+ }
+
+ *quotient = value;
+ *rem = (uint32_t) _rem;
+ }
+
+ /**
+ *-------------------------------------------------------------------------
+ *
+ * mul64x64 --
+ *
+ * This function multiplies two &uint64_t into a &bson_uint128_6464_t.
+ *
+ * Returns:
+ * The product of @left and @right.
+ *
+ * Side Effects:
+ * None.
+ *
+ *-------------------------------------------------------------------------
+ */
+
+ inline
+ void mul_64x64 (uint64_t left, /* IN */
+ uint64_t right, /* IN */
+ bson_uint128_6464_t *product) /* OUT */
+ {
+ uint64_t left_high, left_low, right_high, right_low, product_high,
+ product_mid, product_mid2, product_low;
+ bson_uint128_6464_t rt = {0,0};
+
+ if (!left && !right) {
+ *product = rt;
+ return;
+ }
+
+ left_high = left >> 32;
+ left_low = (uint32_t) left;
+ right_high = right >> 32;
+ right_low = (uint32_t) right;
+
+ product_high = left_high * right_high;
+ product_mid = left_high * right_low;
+ product_mid2 = left_low * right_high;
+ product_low = left_low * right_low;
+
+ product_high += product_mid >> 32;
+ product_mid = (uint32_t) product_mid + product_mid2 + (product_low >> 32);
+
+ product_high = product_high + (product_mid >> 32);
+ product_low = (product_mid << 32) + (uint32_t) product_low;
+
+ rt.high = product_high;
+ rt.low = product_low;
+ *product = rt;
+ }
+
+ /**
+ *------------------------------------------------------------------------------
+ *
+ * dec128_tolower --
+ *
+ * This function converts the ASCII character @c to lowercase. It is locale
+ * insensitive (unlike the stdlib tolower).
+ *
+ * Returns:
+ * The lowercased character.
+ */
+
+ inline
+ char dec128_tolower (char c)
+ {
+ if (isupper (c)) {
+ c += 32;
+ }
+
+ return c;
+ }
+
+ /**
+ *------------------------------------------------------------------------------
+ *
+ * dec128_istreq --
+ *
+ * This function compares the null-terminated *ASCII* strings @a and @b
+ * for case-insensitive equality.
+ *
+ * Returns:
+ * true if the strings are equal, false otherwise.
+ */
+
+ inline
+ bool dec128_istreq (const char* a, const char* lasta,
+ const char* b, const char* lastb)
+ {
+ while (!(a == lasta && b == lastb))
+ {
+ // strings are different lengths
+ if (a == lasta || b == lastb)
+ {
+ return false;
+ }
+
+ if (dec128_tolower (*a) != dec128_tolower (*b)) {
+ return false;
+ }
+
+ a++;
+ b++;
+ }
+
+ return true;
+ }
+
+ } // namespace detail
+
+
+ /**
+ *------------------------------------------------------------------------------
+ *
+ * decimal128_to_chars --
+ *
+ * This function converts a BID formatted decimal128 value to string,
+ * accepting a &decimal128_t as @dec. The string is stored at @str.
+ *
+ * @dec : The BID formatted decimal to convert.
+ * @str : The output decimal128 string. At least %BSON_DECIMAL128_STRING
+ *characters.
+ *
+ * Returns:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *------------------------------------------------------------------------------
+ */
+
+ inline
+ decimal128_to_chars_result decimal128_to_chars(char* first, char* last, const decimal128_t& dec)
+ {
+ const std::string bson_decimal128_inf = "Infinity";
+ const std::string bson_decimal128_nan = "NaN";
+
+ const uint32_t combination_mask = 0x1f; /* Extract least significant 5 bits */
+ const uint32_t exponent_mask = 0x3fff; /* Extract least significant 14 bits */
+ const uint32_t combination_infinity = 30; /* Value of combination field for Inf */
+ const uint32_t combination_nan = 31; /* Value of combination field for NaN */
+ const uint32_t exponent_bias = 6176; /* decimal128 exponent bias */
+
+ char* str_out = first; /* output pointer in string */
+ char significand_str[35]; /* decoded significand digits */
+
+ /* Note: bits in this routine are referred to starting at 0, */
+ /* from the sign bit, towards the coefficient. */
+ uint32_t high; /* bits 0 - 31 */
+ uint32_t midh; /* bits 32 - 63 */
+ uint32_t midl; /* bits 64 - 95 */
+ uint32_t low; /* bits 96 - 127 */
+ uint32_t combination; /* bits 1 - 5 */
+ uint32_t biased_exponent; /* decoded biased exponent (14 bits) */
+ uint32_t significand_digits = 0; /* the number of significand digits */
+ uint32_t significand[36] = {0}; /* the base-10 digits in the significand */
+ uint32_t *significand_read = significand; /* read pointer into significand */
+ int32_t exponent; /* unbiased exponent */
+ int32_t scientific_exponent; /* the exponent if scientific notation is
+ * used */
+ bool is_zero = false; /* true if the number is zero */
+
+ uint8_t significand_msb; /* the most signifcant significand bits (50-46) */
+ bson_uint128_t
+ significand128; /* temporary storage for significand decoding */
+
+ memset (significand_str, 0, sizeof (significand_str));
+
+ if ((int64_t) dec.high < 0) { /* negative */
+ *(str_out++) = '-';
+ }
+
+ low = (uint32_t) dec.low, midl = (uint32_t) (dec.low >> 32),
+ midh = (uint32_t) dec.high, high = (uint32_t) (dec.high >> 32);
+
+ /* Decode combination field and exponent */
+ combination = (high >> 26) & combination_mask;
+
+ if (JSONCONS_UNLIKELY ((combination >> 3) == 3)) {
+ /* Check for 'special' values */
+ if (combination == combination_infinity) { /* Infinity */
+ if (last-str_out >= static_cast<ptrdiff_t >(bson_decimal128_inf.size()))
+ {
+ std::memcpy(str_out, bson_decimal128_inf.data(), bson_decimal128_inf.size());
+ str_out += bson_decimal128_inf.size();
+ }
+ *str_out = 0;
+ //strcpy_s (str_out, last-str_out, bson_decimal128_inf.c_str());
+ return decimal128_to_chars_result{str_out, std::errc()};
+ } else if (combination == combination_nan) { /* NaN */
+ /* first, not str_out, to erase the sign */
+ str_out = first;
+ if (last-str_out >= static_cast<ptrdiff_t >(bson_decimal128_nan.size()))
+ {
+ std::memcpy(str_out, bson_decimal128_nan.data(), bson_decimal128_nan.size());
+ str_out += bson_decimal128_nan.size();
+ }
+ *str_out = 0;
+ //strcpy_s (first, last-first, bson_decimal128_nan.c_str());
+ /* we don't care about the NaN payload. */
+ return decimal128_to_chars_result{str_out, std::errc()};
+ } else {
+ biased_exponent = (high >> 15) & exponent_mask;
+ significand_msb = 0x8 + ((high >> 14) & 0x1);
+ }
+ } else {
+ significand_msb = (high >> 14) & 0x7;
+ biased_exponent = (high >> 17) & exponent_mask;
+ }
+
+ exponent = biased_exponent - exponent_bias;
+ /* Create string of significand digits */
+
+ /* Convert the 114-bit binary number represented by */
+ /* (high, midh, midl, low) to at most 34 decimal */
+ /* digits through modulo and division. */
+ significand128.parts[0] = (high & 0x3fff) + ((significand_msb & 0xf) << 14);
+ significand128.parts[1] = midh;
+ significand128.parts[2] = midl;
+ significand128.parts[3] = low;
+
+ if (significand128.parts[0] == 0 && significand128.parts[1] == 0 &&
+ significand128.parts[2] == 0 && significand128.parts[3] == 0) {
+ is_zero = true;
+ } else if (significand128.parts[0] >= (1 << 17)) {
+ /* The significand is non-canonical or zero.
+ * In order to preserve compatibility with the densely packed decimal
+ * format, the maximum value for the significand of decimal128 is
+ * 1e34 - 1. If the value is greater than 1e34 - 1, the IEEE 754
+ * standard dictates that the significand is interpreted as zero.
+ */
+ is_zero = true;
+ } else {
+ for (int k = 3; k >= 0; k--) {
+ uint32_t least_digits = 0;
+ detail::bson_uint128_divide1B (
+ significand128, &significand128, &least_digits);
+
+ /* We now have the 9 least significant digits (in base 2). */
+ /* Convert and output to string. */
+ if (!least_digits) {
+ continue;
+ }
+
+ for (int j = 8; j >= 0; j--) {
+ significand[k * 9 + j] = least_digits % 10;
+ least_digits /= 10;
+ }
+ }
+ }
+
+ /* Output format options: */
+ /* Scientific - [-]d.dddE(+/-)dd or [-]dE(+/-)dd */
+ /* Regular - ddd.ddd */
+
+ if (is_zero) {
+ significand_digits = 1;
+ *significand_read = 0;
+ } else {
+ significand_digits = 36;
+ while (!(*significand_read)) {
+ significand_digits--;
+ significand_read++;
+ }
+ }
+
+ scientific_exponent = significand_digits - 1 + exponent;
+
+ /* The scientific exponent checks are dictated by the string conversion
+ * specification and are somewhat arbitrary cutoffs.
+ *
+ * We must check exponent > 0, because if this is the case, the number
+ * has trailing zeros. However, we *cannot* output these trailing zeros,
+ * because doing so would change the precision of the value, and would
+ * change stored data if the string converted number is round tripped.
+ */
+ if (scientific_exponent < -6 || exponent > 0) {
+ /* Scientific format */
+ *(str_out++) = char(*(significand_read++)) + '0';
+ significand_digits--;
+
+ if (significand_digits) {
+ *(str_out++) = '.';
+ }
+
+ for (std::size_t i = 0; i < significand_digits && (str_out - first) < 36; i++) {
+ *(str_out++) = char(*(significand_read++)) + '0';
+ }
+ /* Exponent */
+ *(str_out++) = 'E';
+
+ std::string s;
+ if (scientific_exponent >= 0) {
+ s.push_back('+');
+ }
+ jsoncons::detail::from_integer(scientific_exponent, s);
+ if (str_out + s.size() < last)
+ {
+ std::memcpy(str_out, s.data(), s.size());
+ }
+ else
+ {
+ return decimal128_to_chars_result{str_out, std::errc::value_too_large};
+ }
+ str_out += s.size();
+ } else {
+ /* Regular format with no decimal place */
+ if (exponent >= 0) {
+ for (std::size_t i = 0; i < significand_digits && (str_out - first) < 36; i++) {
+ *(str_out++) = char(*(significand_read++)) + '0';
+ }
+ } else {
+ int32_t radix_position = significand_digits + exponent;
+
+ if (radix_position > 0) { /* non-zero digits before radix */
+ for (int32_t i = 0;
+ i < radix_position && (str_out < last);
+ i++) {
+ *(str_out++) = char(*(significand_read++)) + '0';
+ }
+ } else { /* leading zero before radix point */
+ *(str_out++) = '0';
+ }
+
+ *(str_out++) = '.';
+ while (radix_position++ < 0) { /* add leading zeros after radix */
+ *(str_out++) = '0';
+ }
+
+ for (std::size_t i = 0;
+ (i < significand_digits - (std::max) (radix_position - 1, 0)) &&
+ (str_out < last);
+ i++) {
+ *(str_out++) = char(*(significand_read++)) + '0';
+ }
+ }
+ }
+ return decimal128_to_chars_result{str_out, std::errc()};
+ }
+
+
+
+ /**
+ *------------------------------------------------------------------------------
+ *
+ * bson_decimal128_from_string_w_len --
+ *
+ * This function converts @string in the format [+-]ddd[.]ddd[E][+-]dddd to
+ * decimal128. Out of range values are converted to +/-Infinity. Invalid
+ * strings are converted to NaN. @len is the length of the string, or -1
+ * meaning the string is null-terminated.
+ *
+ * If more digits are provided than the available precision allows,
+ * round to the nearest expressable decimal128 with ties going to even will
+ * occur.
+ *
+ * Note: @string must be ASCII only!
+ *
+ * Returns:
+ * true on success, or false on failure. @dec will be NaN if @str was invalid
+ * The &decimal128_t converted from @string at @dec.
+ *
+ * Side effects:
+ * None.
+ *
+ *------------------------------------------------------------------------------
+ */
+
+ inline
+ decimal128_from_chars_result decimal128_from_chars(const char* first, const char* last, decimal128_t& dec)
+ {
+ const string_view inf_str = "inf";
+ const string_view infinity_str = "infinity";
+ const string_view nan_str = "nan";
+
+ ptrdiff_t len = last - first;
+
+ bson_uint128_6464_t significand = {0,0};
+
+ const char* str_read = first; /* Read pointer for consuming str. */
+
+ /* Parsing state tracking */
+ bool is_negative = false;
+ bool saw_radix = false;
+ bool includes_sign = false; /* True if the input first contains a sign. */
+ bool found_nonzero = false;
+
+ size_t significant_digits = 0; /* Total number of significant digits
+ * (no leading or trailing zero) */
+ size_t ndigits_read = 0; /* Total number of significand digits read */
+ size_t ndigits = 0; /* Total number of digits (no leading zeros) */
+ size_t radix_position = 0; /* The number of the digits after radix */
+ size_t first_nonzero = 0; /* The index of the first non-zero in *str* */
+
+ uint16_t digits[decimal128_limits::max_digits] = {0};
+ uint16_t ndigits_stored = 0; /* The number of digits in digits */
+ uint16_t *digits_insert = digits; /* Insertion pointer for digits */
+ size_t first_digit = 0; /* The index of the first non-zero digit */
+ size_t last_digit = 0; /* The index of the last digit */
+
+ int32_t exponent = 0;
+ uint64_t significand_high = 0; /* The high 17 digits of the significand */
+ uint64_t significand_low = 0; /* The low 17 digits of the significand */
+ uint16_t biased_exponent = 0; /* The biased exponent */
+
+ dec.high = 0;
+ dec.low = 0;
+
+ if (*str_read == '+' || *str_read == '-') {
+ is_negative = *(str_read++) == '-';
+ includes_sign = true;
+ }
+
+ /* Check for Infinity or NaN */
+ if (!isdigit (*str_read) && *str_read != '.') {
+ if (detail::dec128_istreq (str_read, last, inf_str.data(), inf_str.data()+inf_str.length()) ||
+ detail::dec128_istreq (str_read, last, infinity_str.data(), infinity_str.data()+infinity_str.length()))
+ {
+ dec = is_negative ? decimal128_limits::neg_infinity() : decimal128_limits::infinity();
+ return decimal128_from_chars_result{str_read,std::errc()};
+ } else if (detail::dec128_istreq (str_read, last, nan_str.data(), nan_str.data()+nan_str.length())) {
+ dec = decimal128_limits::nan();
+ return decimal128_from_chars_result{str_read,std::errc()};
+ }
+
+ dec = decimal128_limits::nan();
+ return decimal128_from_chars_result{str_read,std::errc::invalid_argument};
+ }
+
+ /* Read digits */
+ while (((isdigit (*str_read) || *str_read == '.')) &&
+ (len == -1 || str_read < first + len)) {
+ if (*str_read == '.') {
+ if (saw_radix) {
+ dec = decimal128_limits::nan();
+ return decimal128_from_chars_result{str_read,std::errc::invalid_argument};
+ }
+
+ saw_radix = true;
+ str_read++;
+ continue;
+ }
+
+ if (ndigits_stored < 34) {
+ if (*str_read != '0' || found_nonzero) {
+ if (!found_nonzero) {
+ first_nonzero = ndigits_read;
+ }
+
+ found_nonzero = true;
+ *(digits_insert++) = *(str_read) - '0'; /* Only store 34 digits */
+ ndigits_stored++;
+ }
+ }
+
+ if (found_nonzero) {
+ ndigits++;
+ }
+
+ if (saw_radix) {
+ radix_position++;
+ }
+
+ ndigits_read++;
+ str_read++;
+ }
+
+ if (saw_radix && !ndigits_read) {
+ dec = decimal128_limits::nan();
+ return decimal128_from_chars_result{str_read,std::errc::invalid_argument};
+ }
+
+ /* Read exponent if exists */
+ if (*str_read == 'e' || *str_read == 'E') {
+ ++str_read;
+ if (*str_read == '+') {
+ ++str_read;
+ }
+ auto result = jsoncons::detail::to_integer(str_read, last - str_read, exponent);
+ if (result.ec != jsoncons::detail::to_integer_errc())
+ {
+ dec = decimal128_limits::nan();
+ return decimal128_from_chars_result{str_read,std::errc::invalid_argument};
+ }
+ str_read = result.ptr;
+ }
+
+ if ((len == -1 || str_read < first + len) && *str_read) {
+ dec = decimal128_limits::nan();
+ return decimal128_from_chars_result{str_read,std::errc::invalid_argument};
+ }
+
+ /* Done reading input. */
+ /* Find first non-zero digit in digits */
+ first_digit = 0;
+
+ if (!ndigits_stored) { /* value is zero */
+ first_digit = 0;
+ last_digit = 0;
+ digits[0] = 0;
+ ndigits = 1;
+ ndigits_stored = 1;
+ significant_digits = 0;
+ } else {
+ last_digit = ndigits_stored - 1;
+ significant_digits = ndigits;
+ /* Mark trailing zeros as non-significant */
+ while (first[first_nonzero + significant_digits - 1 + includes_sign +
+ saw_radix] == '0') {
+ significant_digits--;
+ }
+ }
+
+
+ /* Normalization of exponent */
+ /* Correct exponent based on radix position, and shift significand as needed
+ */
+ /* to represent user input */
+
+ /* Overflow prevention */
+ if (exponent <= static_cast<int32_t>(radix_position) && static_cast<int32_t>(radix_position) - exponent > (1 << 14)) {
+ exponent = decimal128_limits::exponent_min;
+ } else {
+ exponent -= static_cast<int32_t>(radix_position);
+ }
+
+ /* Attempt to normalize the exponent */
+ while (exponent > decimal128_limits::exponent_max) {
+ /* Shift exponent to significand and decrease */
+ last_digit++;
+
+ if (last_digit - first_digit > decimal128_limits::max_digits) {
+ /* The exponent is too great to shift into the significand. */
+ if (significant_digits == 0) {
+ /* Value is zero, we are allowed to clamp the exponent. */
+ exponent = decimal128_limits::exponent_max;
+ break;
+ }
+
+ /* Overflow is not permitted, error. */
+ dec = decimal128_limits::nan();
+ return decimal128_from_chars_result{str_read,std::errc::invalid_argument};
+ }
+
+ exponent--;
+ }
+
+ while (exponent < decimal128_limits::exponent_min || ndigits_stored < ndigits) {
+ /* Shift last digit */
+ if (last_digit == 0) {
+ /* underflow is not allowed, but zero clamping is */
+ if (significant_digits == 0) {
+ exponent = decimal128_limits::exponent_min;
+ break;
+ }
+
+ dec = decimal128_limits::nan();
+ return decimal128_from_chars_result{str_read,std::errc::invalid_argument};
+ }
+
+ if (ndigits_stored < ndigits) {
+ if (first[ndigits - 1 + includes_sign + saw_radix] - '0' != 0 &&
+ significant_digits != 0) {
+ dec = decimal128_limits::nan();
+ return decimal128_from_chars_result{str_read,std::errc::invalid_argument};
+ }
+
+ ndigits--; /* adjust to match digits not stored */
+ } else {
+ if (digits[last_digit] != 0) {
+ /* Inexact rounding is not allowed. */
+ dec = decimal128_limits::nan();
+ return decimal128_from_chars_result{str_read,std::errc::invalid_argument};
+ }
+
+
+ last_digit--; /* adjust to round */
+ }
+
+ if (exponent < decimal128_limits::exponent_max) {
+ exponent++;
+ } else {
+ dec = decimal128_limits::nan();
+ return decimal128_from_chars_result{str_read,std::errc::invalid_argument};
+ }
+ }
+
+ /* Round */
+ /* We've normalized the exponent, but might still need to round. */
+ if (last_digit - first_digit + 1 < significant_digits) {
+ uint8_t round_digit;
+
+ /* There are non-zero digits after last_digit that need rounding. */
+ /* We round to nearest, ties to even */
+ round_digit =
+ first[first_nonzero + last_digit + includes_sign + saw_radix + 1] -
+ '0';
+
+ if (round_digit != 0) {
+ /* Inexact (non-zero) rounding is not allowed */
+ dec = decimal128_limits::nan();
+ return decimal128_from_chars_result{str_read,std::errc::invalid_argument};
+ }
+ }
+
+ /* Encode significand */
+ significand_high = 0, /* The high 17 digits of the significand */
+ significand_low = 0; /* The low 17 digits of the significand */
+
+ if (significant_digits == 0) { /* read a zero */
+ significand_high = 0;
+ significand_low = 0;
+ } else if (last_digit - first_digit < 17) {
+ size_t d_idx = first_digit;
+ significand_low = digits[d_idx++];
+
+ for (; d_idx <= last_digit; d_idx++) {
+ significand_low *= 10;
+ significand_low += digits[d_idx];
+ significand_high = 0;
+ }
+ } else {
+ size_t d_idx = first_digit;
+ significand_high = digits[d_idx++];
+
+ for (; d_idx <= last_digit - 17; d_idx++) {
+ significand_high *= 10;
+ significand_high += digits[d_idx];
+ }
+
+ significand_low = digits[d_idx++];
+
+ for (; d_idx <= last_digit; d_idx++) {
+ significand_low *= 10;
+ significand_low += digits[d_idx];
+ }
+ }
+
+ detail::mul_64x64 (significand_high, 100000000000000000ull, &significand);
+ significand.low += significand_low;
+
+ if (significand.low < significand_low) {
+ significand.high += 1;
+ }
+
+
+ biased_exponent = static_cast<uint16_t>(exponent + static_cast<int32_t>(decimal128_limits::exponent_bias));
+
+ /* Encode combination, exponent, and significand. */
+ if ((significand.high >> 49) & 1) {
+ /* Encode '11' into bits 1 to 3 */
+ dec.high |= (0x3ull << 61);
+ dec.high |= (biased_exponent & 0x3fffull) << 47;
+ dec.high |= significand.high & 0x7fffffffffffull;
+ } else {
+ dec.high |= (biased_exponent & 0x3fffull) << 49;
+ dec.high |= significand.high & 0x1ffffffffffffull;
+ }
+
+ dec.low = significand.low;
+
+ /* Encode sign */
+ if (is_negative) {
+ dec.high |= 0x8000000000000000ull;
+ }
+
+ return decimal128_from_chars_result{str_read,std::errc()};
+ }
+
+} // namespace bson
+} // namespace jsoncons
+
+#endif