Add wuffs_base__render_number_f64
diff --git a/internal/cgen/base/f64conv-submodule.c b/internal/cgen/base/f64conv-submodule.c
index e0b79d7..5e48340 100644
--- a/internal/cgen/base/f64conv-submodule.c
+++ b/internal/cgen/base/f64conv-submodule.c
@@ -16,8 +16,8 @@
// ---------------- IEEE 754 Floating Point
-#define WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DECIMAL_POINT__RANGE 1023
-#define WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DIGITS_PRECISION 500
+#define WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DECIMAL_POINT__RANGE 2047
+#define WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DIGITS_PRECISION 800
// WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__SHIFT__MAX_INCL is the largest N
// such that ((10 << N) < (1 << 64)).
@@ -27,14 +27,14 @@
// fixed precision floating point decimal number, augmented with ±infinity
// values, but it cannot represent NaN (Not a Number).
//
-// "High precision" means that the mantissa holds 500 decimal digits. 500 is
+// "High precision" means that the mantissa holds 800 decimal digits. 800 is
// WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DIGITS_PRECISION.
//
// An HPD isn't for general purpose arithmetic, only for conversions to and
// from IEEE 754 double-precision floating point, where the largest and
// smallest positive, finite values are approximately 1.8e+308 and 4.9e-324.
-// HPD exponents above +1023 mean infinity, below -1023 mean zero. The ±1023
-// bounds are further away from zero than ±(324 + 500), where 500 and 1023 is
+// HPD exponents above +2047 mean infinity, below -2047 mean zero. The ±2047
+// bounds are further away from zero than ±(324 + 800), where 800 and 2047 is
// WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DIGITS_PRECISION and
// WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DECIMAL_POINT__RANGE.
//
@@ -56,8 +56,8 @@
// - A decimal_point of +4 means "7890."
// - A decimal_point of +5 means "78900."
//
-// As above, a decimal_point higher than +1023 means that the overall value is
-// infinity, lower than -1023 means zero.
+// As above, a decimal_point higher than +2047 means that the overall value is
+// infinity, lower than -2047 means zero.
//
// negative is a sign bit. An HPD can distinguish positive and negative zero.
//
@@ -89,6 +89,48 @@
}
}
+// wuffs_base__private_implementation__high_prec_dec__assign sets h to
+// represent the number x.
+//
+// Preconditions:
+// - h is non-NULL.
+static void //
+wuffs_base__private_implementation__high_prec_dec__assign(
+ wuffs_base__private_implementation__high_prec_dec* h,
+ uint64_t x,
+ bool negative) {
+ uint32_t n = 0;
+
+ // Set h->digits.
+ if (x > 0) {
+ // Calculate the digits, working right-to-left. After we determine n (how
+ // many digits there are), copy from buf to h->digits.
+ //
+ // UINT64_MAX, 18446744073709551615, is 20 digits long. It can be faster to
+ // copy a constant number of bytes than a variable number (20 instead of
+ // n). Make buf large enough (and start writing to it from the middle) so
+ // that can we always copy 20 bytes: the slice buf[(20-n) .. (40-n)].
+ uint8_t buf[40] = {0};
+ uint8_t* ptr = &buf[20];
+ do {
+ uint64_t remaining = x / 10;
+ x -= remaining * 10;
+ ptr--;
+ *ptr = (uint8_t)x;
+ n++;
+ x = remaining;
+ } while (x > 0);
+ memcpy(h->digits, ptr, 20);
+ }
+
+ // Set h's other fields.
+ h->num_digits = n;
+ h->decimal_point = (int32_t)n;
+ h->negative = negative;
+ h->truncated = false;
+ wuffs_base__private_implementation__high_prec_dec__trim(h);
+}
+
static wuffs_base__status //
wuffs_base__private_implementation__high_prec_dec__parse(
wuffs_base__private_implementation__high_prec_dec* h,
@@ -464,6 +506,11 @@
// wuffs_base__private_implementation__high_prec_dec__rounded_integer and
// wuffs_base__private_implementation__high_prec_dec__lshift_num_new_digits
// have the same preconditions.
+//
+// wuffs_base__private_implementation__high_prec_dec__lshift keeps the first
+// two preconditions but not the last two. Its shift argument is signed and
+// does not need to be "small": zero is a no-op, positive means left shift and
+// negative means right shift.
static void //
wuffs_base__private_implementation__high_prec_dec__small_lshift(
@@ -577,6 +624,254 @@
wuffs_base__private_implementation__high_prec_dec__trim(h);
}
+static void //
+wuffs_base__private_implementation__high_prec_dec__lshift(
+ wuffs_base__private_implementation__high_prec_dec* h,
+ int32_t shift) {
+ if (shift > 0) {
+ while (shift > +WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__SHIFT__MAX_INCL) {
+ wuffs_base__private_implementation__high_prec_dec__small_lshift(
+ h, WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__SHIFT__MAX_INCL);
+ shift -= WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__SHIFT__MAX_INCL;
+ }
+ wuffs_base__private_implementation__high_prec_dec__small_lshift(
+ h, ((uint32_t)(+shift)));
+ } else if (shift < 0) {
+ while (shift < -WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__SHIFT__MAX_INCL) {
+ wuffs_base__private_implementation__high_prec_dec__small_rshift(
+ h, WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__SHIFT__MAX_INCL);
+ shift += WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__SHIFT__MAX_INCL;
+ }
+ wuffs_base__private_implementation__high_prec_dec__small_rshift(
+ h, ((uint32_t)(-shift)));
+ }
+}
+
+// --------
+
+// wuffs_base__private_implementation__high_prec_dec__round_etc rounds h's
+// number. For those functions that take an n argument, rounding produces at
+// most n digits (which is not necessarily at most n decimal places). Negative
+// n values are ignored, as well as any n greater than or equal to h's number
+// of digits. The etc__round_just_enough function implicitly chooses an n to
+// implement WUFFS_BASE__RENDER_NUMBER_FXX__JUST_ENOUGH_PRECISION.
+//
+// Preconditions:
+// - h is non-NULL.
+// - h->decimal_point is "not extreme".
+//
+// "Not extreme" means within
+// ±WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DECIMAL_POINT__RANGE.
+
+static void //
+wuffs_base__private_implementation__high_prec_dec__round_down(
+ wuffs_base__private_implementation__high_prec_dec* h,
+ int32_t n) {
+ if ((n < 0) || (h->num_digits <= (uint32_t)n)) {
+ return;
+ }
+ h->num_digits = (uint32_t)(n);
+ wuffs_base__private_implementation__high_prec_dec__trim(h);
+}
+
+static void //
+wuffs_base__private_implementation__high_prec_dec__round_up(
+ wuffs_base__private_implementation__high_prec_dec* h,
+ int32_t n) {
+ if ((n < 0) || (h->num_digits <= (uint32_t)n)) {
+ return;
+ }
+
+ for (n--; n >= 0; n--) {
+ if (h->digits[n] < 9) {
+ h->digits[n]++;
+ h->num_digits = (uint32_t)(n + 1);
+ return;
+ }
+ }
+
+ // The number is all 9s. Change to a single 1 and adjust the decimal point.
+ h->digits[0] = 1;
+ h->num_digits = 1;
+ h->decimal_point++;
+}
+
+static void //
+wuffs_base__private_implementation__high_prec_dec__round_nearest(
+ wuffs_base__private_implementation__high_prec_dec* h,
+ int32_t n) {
+ if ((n < 0) || (h->num_digits <= (uint32_t)n)) {
+ return;
+ }
+ bool up = h->digits[n] >= 5;
+ if ((h->digits[n] == 5) && ((n + 1) == ((int32_t)(h->num_digits)))) {
+ up = h->truncated || //
+ ((n > 0) && ((h->digits[n - 1] & 1) != 0));
+ }
+
+ if (up) {
+ wuffs_base__private_implementation__high_prec_dec__round_up(h, n);
+ } else {
+ wuffs_base__private_implementation__high_prec_dec__round_down(h, n);
+ }
+}
+
+static void //
+wuffs_base__private_implementation__high_prec_dec__round_just_enough(
+ wuffs_base__private_implementation__high_prec_dec* h,
+ int32_t exp2,
+ uint64_t mantissa) {
+ // The magic numbers 52 and 53 in this function are because IEEE 754 double
+ // precision has 52 mantissa bits.
+ //
+ // Let f be the floating point number represented by exp2 and mantissa (and
+ // also the number in h): the number (mantissa * (2 ** (exp2 - 52))).
+ //
+ // If f is zero, we can return early.
+ if (mantissa == 0) {
+ return;
+ }
+
+ // The smallest normal f has an exp2 of -1022 and a mantissa of (1 << 52).
+ // Subnormal numbers have the same exp2 but a smaller mantissa.
+ static const int32_t min_incl_normal_exp2 = -1022;
+ static const uint64_t min_incl_normal_mantissa = 0x0010000000000000ul;
+
+ // Compute lower and upper bounds such that any number between them (possibly
+ // inclusive) will round to f. First, the lower bound. Our number f is:
+ // ((mantissa + 0) * (2 ** ( exp2 - 52)))
+ //
+ // The next lowest floating point number is:
+ // ((mantissa - 1) * (2 ** ( exp2 - 52)))
+ // unless (mantissa - 1) drops the (1 << 52) bit and exp2 is not the
+ // min_incl_normal_exp2. Either way, call it:
+ // ((l_mantissa) * (2 ** (l_exp2 - 52)))
+ //
+ // The lower bound is halfway between them (noting that 52 became 53):
+ // (((2 * l_mantissa) + 1) * (2 ** (l_exp2 - 53)))
+ int32_t l_exp2 = exp2;
+ uint64_t l_mantissa = mantissa - 1;
+ if ((exp2 > min_incl_normal_exp2) && (mantissa <= min_incl_normal_mantissa)) {
+ l_exp2 = exp2 - 1;
+ l_mantissa = (2 * mantissa) - 1;
+ }
+ wuffs_base__private_implementation__high_prec_dec lower;
+ wuffs_base__private_implementation__high_prec_dec__assign(
+ &lower, (2 * l_mantissa) + 1, false);
+ wuffs_base__private_implementation__high_prec_dec__lshift(&lower,
+ l_exp2 - 53);
+
+ // Next, the upper bound. Our number f is:
+ // ((mantissa + 0) * (2 ** (exp2 - 52)))
+ //
+ // The next highest floating point number is:
+ // ((mantissa + 1) * (2 ** (exp2 - 52)))
+ //
+ // The upper bound is halfway between them (noting that 52 became 53):
+ // (((2 * mantissa) + 1) * (2 ** (exp2 - 53)))
+ wuffs_base__private_implementation__high_prec_dec upper;
+ wuffs_base__private_implementation__high_prec_dec__assign(
+ &upper, (2 * mantissa) + 1, false);
+ wuffs_base__private_implementation__high_prec_dec__lshift(&upper, exp2 - 53);
+
+ // The lower and upper bounds are possible outputs only if the original
+ // mantissa is even, so that IEEE round-to-even would round to the original
+ // mantissa and not its neighbors.
+ bool inclusive = (mantissa & 1) == 0;
+
+ // As we walk the digits, we want to know whether rounding up would fall
+ // within the upper bound. This is tracked by upper_delta:
+ // - When -1, the digits of h and upper are the same so far.
+ // - When +0, we saw a difference of 1 between h and upper on a previous
+ // digit and subsequently only 9s for h and 0s for upper. Thus, rounding
+ // up may fall outside of the bound if !inclusive.
+ // - When +1, the difference is greater than 1 and we know that rounding up
+ // falls within the bound.
+ //
+ // This is a state machine with three states. The numerical value for each
+ // state (-1, +0 or +1) isn't important, other than their order.
+ int upper_delta = -1;
+
+ // We can now figure out the shortest number of digits required. Walk the
+ // digits until h has distinguished itself from lower or upper.
+ //
+ // The zi and zd variables are indexes and digits, for z in l (lower), h (the
+ // number) and u (upper).
+ //
+ // The lower, h and upper numbers may have their decimal points at different
+ // places. In this case, upper is the longest, so we iterate ui starting from
+ // 0 and iterate li and hi starting from either 0 or -1.
+ int32_t ui = 0;
+ for (;; ui++) {
+ // Calculate hd, the middle number's digit.
+ int32_t hi = ui - upper.decimal_point + h->decimal_point;
+ if (hi >= ((int32_t)(h->num_digits))) {
+ break;
+ }
+ uint8_t hd = (((uint32_t)hi) < h->num_digits) ? h->digits[hi] : 0;
+
+ // Calculate ld, the lower bound's digit.
+ int32_t li = ui - upper.decimal_point + lower.decimal_point;
+ uint8_t ld = (((uint32_t)li) < lower.num_digits) ? lower.digits[li] : 0;
+
+ // We can round down (truncate) if lower has a different digit than h or if
+ // lower is inclusive and is exactly the result of rounding down (i.e. we
+ // have reached the final digit of lower).
+ bool can_round_down =
+ (ld != hd) || //
+ (inclusive && ((li + 1) == ((int32_t)(lower.num_digits))));
+
+ // Calculate ud, the upper bound's digit, and update upper_delta.
+ uint8_t ud = (((uint32_t)ui) < upper.num_digits) ? upper.digits[ui] : 0;
+ if (upper_delta < 0) {
+ if ((hd + 1) < ud) {
+ // For example:
+ // h = 12345???
+ // upper = 12347???
+ upper_delta = +1;
+ } else if (hd != ud) {
+ // For example:
+ // h = 12345???
+ // upper = 12346???
+ upper_delta = +0;
+ }
+ } else if (upper_delta == 0) {
+ if ((hd != 9) || (ud != 0)) {
+ // For example:
+ // h = 1234598?
+ // upper = 1234600?
+ upper_delta = +1;
+ }
+ }
+
+ // We can round up if upper has a different digit than h and either upper
+ // is inclusive or upper is bigger than the result of rounding up.
+ bool can_round_up =
+ (upper_delta > 0) || //
+ ((upper_delta == 0) && //
+ (inclusive || ((ui + 1) < ((int32_t)(upper.num_digits)))));
+
+ // If we can round either way, round to nearest. If we can round only one
+ // way, do it. If we can't round, continue the loop.
+ if (can_round_down) {
+ if (can_round_up) {
+ wuffs_base__private_implementation__high_prec_dec__round_nearest(
+ h, hi + 1);
+ return;
+ } else {
+ wuffs_base__private_implementation__high_prec_dec__round_down(h,
+ hi + 1);
+ return;
+ }
+ } else {
+ if (can_round_up) {
+ wuffs_base__private_implementation__high_prec_dec__round_up(h, hi + 1);
+ return;
+ }
+ }
+ }
+}
+
// --------
// The wuffs_base__private_implementation__etc_powers_of_10 tables were printed
@@ -1262,3 +1557,300 @@
return ret;
} while (0);
}
+
+// --------
+
+static inline size_t //
+wuffs_base__private_implementation__render_inf(wuffs_base__slice_u8 dst,
+ bool neg,
+ uint32_t options) {
+ if (neg) {
+ if (dst.len < 4) {
+ return 0;
+ }
+ wuffs_base__store_u32le__no_bounds_check(dst.ptr, 0x666E492D); // '-Inf'le.
+ return 4;
+ }
+
+ if (options & WUFFS_BASE__RENDER_NUMBER_XXX__LEADING_PLUS_SIGN) {
+ if (dst.len < 4) {
+ return 0;
+ }
+ wuffs_base__store_u32le__no_bounds_check(dst.ptr, 0x666E492B); // '+Inf'le.
+ return 4;
+ }
+
+ if (dst.len < 3) {
+ return 0;
+ }
+ wuffs_base__store_u24le__no_bounds_check(dst.ptr, 0x666E49); // 'Inf'le.
+ return 3;
+}
+
+static inline size_t //
+wuffs_base__private_implementation__render_nan(wuffs_base__slice_u8 dst) {
+ if (dst.len < 3) {
+ return 0;
+ }
+ wuffs_base__store_u24le__no_bounds_check(dst.ptr, 0x4E614E); // 'NaN'le.
+ return 3;
+}
+
+static size_t //
+wuffs_base__private_implementation__high_prec_dec__render_exponent_absent(
+ wuffs_base__slice_u8 dst,
+ wuffs_base__private_implementation__high_prec_dec* h,
+ uint32_t precision,
+ uint32_t options) {
+ size_t n = (h->negative ||
+ (options & WUFFS_BASE__RENDER_NUMBER_XXX__LEADING_PLUS_SIGN))
+ ? 1
+ : 0;
+ if (h->decimal_point <= 0) {
+ n += 1;
+ } else {
+ n += (size_t)(h->decimal_point);
+ }
+ if (precision > 0) {
+ n += precision + 1; // +1 for the '.'.
+ }
+
+ // Don't modify dst if the formatted number won't fit.
+ if (n > dst.len) {
+ return 0;
+ }
+
+ // Align-left or align-right.
+ uint8_t* ptr = (options & WUFFS_BASE__RENDER_NUMBER_XXX__ALIGN_RIGHT)
+ ? &dst.ptr[dst.len - n]
+ : &dst.ptr[0];
+
+ // Leading "±".
+ if (h->negative) {
+ *ptr++ = '-';
+ } else if (options & WUFFS_BASE__RENDER_NUMBER_XXX__LEADING_PLUS_SIGN) {
+ *ptr++ = '+';
+ }
+
+ // Integral digits.
+ if (h->decimal_point <= 0) {
+ *ptr++ = '0';
+ } else {
+ uint32_t m =
+ wuffs_base__u32__min(h->num_digits, (uint32_t)(h->decimal_point));
+ uint32_t i = 0;
+ for (; i < m; i++) {
+ *ptr++ = (uint8_t)('0' | h->digits[i]);
+ }
+ for (; i < (uint32_t)(h->decimal_point); i++) {
+ *ptr++ = '0';
+ }
+ }
+
+ // Separator and then fractional digits.
+ if (precision > 0) {
+ *ptr++ =
+ (options & WUFFS_BASE__RENDER_NUMBER_FXX__DECIMAL_SEPARATOR_IS_A_COMMA)
+ ? ','
+ : '.';
+ uint32_t i = 0;
+ for (; i < precision; i++) {
+ uint32_t j = ((uint32_t)(h->decimal_point)) + i;
+ *ptr++ = (uint8_t)('0' | ((j < h->num_digits) ? h->digits[j] : 0));
+ }
+ }
+
+ return n;
+}
+
+static size_t //
+wuffs_base__private_implementation__high_prec_dec__render_exponent_present(
+ wuffs_base__slice_u8 dst,
+ wuffs_base__private_implementation__high_prec_dec* h,
+ uint32_t precision,
+ uint32_t options) {
+ int32_t exp = 0;
+ if (h->num_digits > 0) {
+ exp = h->decimal_point - 1;
+ }
+ bool negative_exp = exp < 0;
+ if (negative_exp) {
+ exp = -exp;
+ }
+
+ size_t n = (h->negative ||
+ (options & WUFFS_BASE__RENDER_NUMBER_XXX__LEADING_PLUS_SIGN))
+ ? 4
+ : 3; // Mininum 3 bytes: first digit and then "e±".
+ if (precision > 0) {
+ n += precision + 1; // +1 for the '.'.
+ }
+ n += (exp < 100) ? 2 : 3;
+
+ // Don't modify dst if the formatted number won't fit.
+ if (n > dst.len) {
+ return 0;
+ }
+
+ // Align-left or align-right.
+ uint8_t* ptr = (options & WUFFS_BASE__RENDER_NUMBER_XXX__ALIGN_RIGHT)
+ ? &dst.ptr[dst.len - n]
+ : &dst.ptr[0];
+
+ // Leading "±".
+ if (h->negative) {
+ *ptr++ = '-';
+ } else if (options & WUFFS_BASE__RENDER_NUMBER_XXX__LEADING_PLUS_SIGN) {
+ *ptr++ = '+';
+ }
+
+ // Integral digit.
+ if (h->num_digits > 0) {
+ *ptr++ = (uint8_t)('0' | h->digits[0]);
+ } else {
+ *ptr++ = '0';
+ }
+
+ // Separator and then fractional digits.
+ if (precision > 0) {
+ *ptr++ =
+ (options & WUFFS_BASE__RENDER_NUMBER_FXX__DECIMAL_SEPARATOR_IS_A_COMMA)
+ ? ','
+ : '.';
+ uint32_t i = 1;
+ uint32_t j = wuffs_base__u32__min(h->num_digits, precision + 1);
+ for (; i < j; i++) {
+ *ptr++ = (uint8_t)('0' | h->digits[i]);
+ }
+ for (; i <= precision; i++) {
+ *ptr++ = '0';
+ }
+ }
+
+ // Exponent: "e±" and then 2 or 3 digits.
+ *ptr++ = 'e';
+ *ptr++ = negative_exp ? '-' : '+';
+ if (exp < 10) {
+ *ptr++ = '0';
+ *ptr++ = (uint8_t)('0' | exp);
+ } else if (exp < 100) {
+ *ptr++ = (uint8_t)('0' | (exp / 10));
+ *ptr++ = (uint8_t)('0' | (exp % 10));
+ } else {
+ int32_t e = exp / 100;
+ exp -= e * 100;
+ *ptr++ = (uint8_t)('0' | e);
+ *ptr++ = (uint8_t)('0' | (exp / 10));
+ *ptr++ = (uint8_t)('0' | (exp % 10));
+ }
+
+ return n;
+}
+
+WUFFS_BASE__MAYBE_STATIC size_t //
+wuffs_base__render_number_f64(wuffs_base__slice_u8 dst,
+ double x,
+ uint32_t precision,
+ uint32_t options) {
+ // Decompose x (64 bits) into negativity (1 bit), base-2 exponent (11 bits
+ // with a -1023 bias) and mantissa (52 bits).
+ uint64_t bits = wuffs_base__ieee_754_bit_representation__from_f64(x);
+ bool neg = (bits >> 63) != 0;
+ int32_t exp2 = ((int32_t)(bits >> 52)) & 0x7FF;
+ uint64_t man = bits & 0x000FFFFFFFFFFFFFul;
+
+ // Apply the exponent bias and set the implicit top bit of the mantissa,
+ // unless x is subnormal. Also take care of Inf and NaN.
+ if (exp2 == 0x7FF) {
+ if (man != 0) {
+ return wuffs_base__private_implementation__render_nan(dst);
+ }
+ return wuffs_base__private_implementation__render_inf(dst, neg, options);
+ } else if (exp2 == 0) {
+ exp2 = -1022;
+ } else {
+ exp2 -= 1023;
+ man |= 0x0010000000000000ul;
+ }
+
+ // Ensure that precision isn't too large.
+ if (precision > 4095) {
+ precision = 4095;
+ }
+
+ // Convert from the (neg, exp2, man) tuple to an HPD.
+ wuffs_base__private_implementation__high_prec_dec h;
+ wuffs_base__private_implementation__high_prec_dec__assign(&h, man, neg);
+ if (h.num_digits > 0) {
+ wuffs_base__private_implementation__high_prec_dec__lshift(
+ &h, exp2 - 52); // 52 mantissa bits.
+ }
+
+ // Handle the "%e" and "%f" formats.
+ switch (options & (WUFFS_BASE__RENDER_NUMBER_FXX__EXPONENT_ABSENT |
+ WUFFS_BASE__RENDER_NUMBER_FXX__EXPONENT_PRESENT)) {
+ case WUFFS_BASE__RENDER_NUMBER_FXX__EXPONENT_ABSENT: // The "%"f" format.
+ if (options & WUFFS_BASE__RENDER_NUMBER_FXX__JUST_ENOUGH_PRECISION) {
+ wuffs_base__private_implementation__high_prec_dec__round_just_enough(
+ &h, exp2, man);
+ int32_t p = ((int32_t)(h.num_digits)) - h.decimal_point;
+ precision = ((uint32_t)(wuffs_base__i32__max(0, p)));
+ } else {
+ wuffs_base__private_implementation__high_prec_dec__round_nearest(
+ &h, ((int32_t)precision) + h.decimal_point);
+ }
+ return wuffs_base__private_implementation__high_prec_dec__render_exponent_absent(
+ dst, &h, precision, options);
+
+ case WUFFS_BASE__RENDER_NUMBER_FXX__EXPONENT_PRESENT: // The "%e" format.
+ if (options & WUFFS_BASE__RENDER_NUMBER_FXX__JUST_ENOUGH_PRECISION) {
+ wuffs_base__private_implementation__high_prec_dec__round_just_enough(
+ &h, exp2, man);
+ precision = (h.num_digits > 0) ? (h.num_digits - 1) : 0;
+ } else {
+ wuffs_base__private_implementation__high_prec_dec__round_nearest(
+ &h, ((int32_t)precision) + 1);
+ }
+ return wuffs_base__private_implementation__high_prec_dec__render_exponent_present(
+ dst, &h, precision, options);
+ }
+
+ // We have the "%g" format and so precision means the number of significant
+ // digits, not the number of digits after the decimal separator. Perform
+ // rounding and determine whether to use "%e" or "%f".
+ int32_t e_threshold = 0;
+ if (options & WUFFS_BASE__RENDER_NUMBER_FXX__JUST_ENOUGH_PRECISION) {
+ wuffs_base__private_implementation__high_prec_dec__round_just_enough(
+ &h, exp2, man);
+ precision = h.num_digits;
+ e_threshold = 6;
+ } else {
+ if (precision == 0) {
+ precision = 1;
+ }
+ wuffs_base__private_implementation__high_prec_dec__round_nearest(
+ &h, ((int32_t)precision));
+ e_threshold = ((int32_t)precision);
+ int32_t nd = ((int32_t)(h.num_digits));
+ if ((e_threshold > nd) && (nd >= h.decimal_point)) {
+ e_threshold = nd;
+ }
+ }
+
+ // Use the "%e" format if the exponent is large.
+ int32_t e = h.decimal_point - 1;
+ if ((e < -4) || (e_threshold <= e)) {
+ uint32_t p = wuffs_base__u32__min(precision, h.num_digits);
+ return wuffs_base__private_implementation__high_prec_dec__render_exponent_present(
+ dst, &h, (p > 0) ? (p - 1) : 0, options);
+ }
+
+ // Use the "%f" format otherwise.
+ int32_t p = ((int32_t)precision);
+ if (p > h.decimal_point) {
+ p = ((int32_t)(h.num_digits));
+ }
+ precision = ((uint32_t)(wuffs_base__i32__max(0, p - h.decimal_point)));
+ return wuffs_base__private_implementation__high_prec_dec__render_exponent_absent(
+ dst, &h, precision, options);
+}
diff --git a/internal/cgen/base/fundamental-public.h b/internal/cgen/base/fundamental-public.h
index f69e2e4..55c0d40 100644
--- a/internal/cgen/base/fundamental-public.h
+++ b/internal/cgen/base/fundamental-public.h
@@ -281,6 +281,46 @@
// inline attribute to guide optimizations such as inlining, to avoid the
// -Wunused-function warning, and we like to compile with -Wall -Werror.
+static inline int8_t //
+wuffs_base__i8__min(int8_t x, int8_t y) {
+ return x < y ? x : y;
+}
+
+static inline int8_t //
+wuffs_base__i8__max(int8_t x, int8_t y) {
+ return x > y ? x : y;
+}
+
+static inline int16_t //
+wuffs_base__i16__min(int16_t x, int16_t y) {
+ return x < y ? x : y;
+}
+
+static inline int16_t //
+wuffs_base__i16__max(int16_t x, int16_t y) {
+ return x > y ? x : y;
+}
+
+static inline int32_t //
+wuffs_base__i32__min(int32_t x, int32_t y) {
+ return x < y ? x : y;
+}
+
+static inline int32_t //
+wuffs_base__i32__max(int32_t x, int32_t y) {
+ return x > y ? x : y;
+}
+
+static inline int64_t //
+wuffs_base__i64__min(int64_t x, int64_t y) {
+ return x < y ? x : y;
+}
+
+static inline int64_t //
+wuffs_base__i64__max(int64_t x, int64_t y) {
+ return x > y ? x : y;
+}
+
static inline uint8_t //
wuffs_base__u8__min(uint8_t x, uint8_t y) {
return x < y ? x : y;
diff --git a/internal/cgen/base/i64conv-submodule.c b/internal/cgen/base/i64conv-submodule.c
index 86335d2..6c43523 100644
--- a/internal/cgen/base/i64conv-submodule.c
+++ b/internal/cgen/base/i64conv-submodule.c
@@ -359,7 +359,7 @@
if (neg) {
ptr -= 1;
ptr[0] = '-';
- } else if (options & WUFFS_BASE__RENDER_NUMBER__LEADING_PLUS_SIGN) {
+ } else if (options & WUFFS_BASE__RENDER_NUMBER_XXX__LEADING_PLUS_SIGN) {
ptr -= 1;
ptr[0] = '+';
}
@@ -368,7 +368,7 @@
if (n > dst.len) {
return 0;
}
- memcpy(dst.ptr + ((options & WUFFS_BASE__RENDER_NUMBER__ALIGN_RIGHT)
+ memcpy(dst.ptr + ((options & WUFFS_BASE__RENDER_NUMBER_XXX__ALIGN_RIGHT)
? (dst.len - n)
: 0),
ptr, n);
diff --git a/internal/cgen/base/strconv-public.h b/internal/cgen/base/strconv-public.h
index 4f80c2a..734d60c 100644
--- a/internal/cgen/base/strconv-public.h
+++ b/internal/cgen/base/strconv-public.h
@@ -16,20 +16,49 @@
// ---------------- String Conversions
-// Options (bitwise or'ed together) for wuffs_base__render_number_etc
-// functions.
+// Options (bitwise or'ed together) for wuffs_base__render_number_xxx
+// functions. The XXX options apply to both integer and floating point. The FXX
+// options apply only to floating point.
-#define WUFFS_BASE__RENDER_NUMBER__DEFAULT_OPTIONS ((uint32_t)0x00000000)
+#define WUFFS_BASE__RENDER_NUMBER_XXX__DEFAULT_OPTIONS ((uint32_t)0x00000000)
-// WUFFS_BASE__RENDER_NUMBER__ALIGN_RIGHT means to render to the right side
+// WUFFS_BASE__RENDER_NUMBER_XXX__ALIGN_RIGHT means to render to the right side
// (higher indexes) of the destination slice, leaving any untouched bytes on
// the left side (lower indexes). The default is vice versa: rendering on the
// left with slack on the right.
-#define WUFFS_BASE__RENDER_NUMBER__ALIGN_RIGHT ((uint32_t)0x00000001)
+#define WUFFS_BASE__RENDER_NUMBER_XXX__ALIGN_RIGHT ((uint32_t)0x00000001)
-// WUFFS_BASE__RENDER_NUMBER__LEADING_PLUS_SIGN means to render the unnecessary
-// leading "+" for non-negative numbers: "+0" and "+123", not "0" and "123".
-#define WUFFS_BASE__RENDER_NUMBER__LEADING_PLUS_SIGN ((uint32_t)0x00000002)
+// WUFFS_BASE__RENDER_NUMBER_XXX__LEADING_PLUS_SIGN means to render the leading
+// "+" for non-negative numbers: "+0" and "+12.3" instead of "0" and "12.3".
+#define WUFFS_BASE__RENDER_NUMBER_XXX__LEADING_PLUS_SIGN ((uint32_t)0x00000002)
+
+// WUFFS_BASE__RENDER_NUMBER_FXX__DECIMAL_SEPARATOR_IS_A_COMMA means to render
+// one-and-a-half as "1,5" instead of "1.5".
+#define WUFFS_BASE__RENDER_NUMBER_FXX__DECIMAL_SEPARATOR_IS_A_COMMA \
+ ((uint32_t)0x00000100)
+
+// WUFFS_BASE__RENDER_NUMBER_FXX__EXPONENT_ETC means whether to never
+// (EXPONENT_ABSENT, equivalent to printf's "%f") or to always
+// (EXPONENT_PRESENT, equivalent to printf's "%e") render a floating point
+// number as "1.23e+05" instead of "123000".
+//
+// Having both bits set is the same has having neither bit set, where the
+// notation used depends on whether the exponent is sufficiently large: "0.5"
+// is preferred over "5e-01" but "5e-09" is preferred over "0.000000005".
+#define WUFFS_BASE__RENDER_NUMBER_FXX__EXPONENT_ABSENT ((uint32_t)0x00000200)
+#define WUFFS_BASE__RENDER_NUMBER_FXX__EXPONENT_PRESENT ((uint32_t)0x00000400)
+
+// WUFFS_BASE__RENDER_NUMBER_FXX__JUST_ENOUGH_PRECISION means to render the
+// smallest number of digits so that parsing the resultant string will recover
+// the same double-precision floating point number.
+//
+// For example, double-precision cannot distinguish between 0.3 and
+// 0.299999999999999988897769753748434595763683319091796875, so when this bit
+// is set, rendering the latter will produce "0.3" but rendering
+// 0.3000000000000000444089209850062616169452667236328125 will produce
+// "0.30000000000000004".
+#define WUFFS_BASE__RENDER_NUMBER_FXX__JUST_ENOUGH_PRECISION \
+ ((uint32_t)0x00000800)
// ---------------- IEEE 754 Floating Point
@@ -148,6 +177,38 @@
#define WUFFS_BASE__I64__BYTE_LENGTH__MAX_INCL 20
#define WUFFS_BASE__U64__BYTE_LENGTH__MAX_INCL 21
+// wuffs_base__render_number_f64 writes the decimal encoding of x to dst and
+// returns the number of bytes written. If dst is shorter than the entire
+// encoding, it returns 0 (and no bytes are written).
+//
+// For those familiar with C's printf or Go's fmt.Printf functions:
+// - "%e" means the WUFFS_BASE__RENDER_NUMBER_FXX__EXPONENT_PRESENT option.
+// - "%f" means the WUFFS_BASE__RENDER_NUMBER_FXX__EXPONENT_ABSENT option.
+// - "%g" means neither or both bits are set.
+//
+// The precision argument controls the number of digits rendered, excluding the
+// exponent (the "e+05" in "1.23e+05"):
+// - for "%e" and "%f" it is the number of digits after the decimal separator,
+// - for "%g" it is the number of significant digits (and trailing zeroes are
+// removed).
+//
+// A precision of 6 gives similar output to printf's defaults.
+//
+// A precision greater than 4095 is equivalent to 4095.
+//
+// The precision argument is ignored when the
+// WUFFS_BASE__RENDER_NUMBER_FXX__JUST_ENOUGH_PRECISION option is set. This is
+// similar to Go's strconv.FormatFloat with a negative (i.e. non-sensical)
+// precision, but there is no corresponding feature in C's printf.
+//
+// Extreme values of x will be rendered as "NaN", "Inf" (or "+Inf" if the
+// WUFFS_BASE__RENDER_NUMBER_XXX__LEADING_PLUS_SIGN option is set) or "-Inf".
+WUFFS_BASE__MAYBE_STATIC size_t //
+wuffs_base__render_number_f64(wuffs_base__slice_u8 dst,
+ double x,
+ uint32_t precision,
+ uint32_t options);
+
// wuffs_base__render_number_i64 writes the decimal encoding of x to dst and
// returns the number of bytes written. If dst is shorter than the entire
// encoding, it returns 0 (and no bytes are written).
diff --git a/internal/cgen/data/data.go b/internal/cgen/data/data.go
index e39b9c6..ae40721 100644
--- a/internal/cgen/data/data.go
+++ b/internal/cgen/data/data.go
@@ -29,14 +29,15 @@
""
const BaseF64ConvSubmoduleC = "" +
- "// ---------------- IEEE 754 Floating Point\n\n#define WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DECIMAL_POINT__RANGE 1023\n#define WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DIGITS_PRECISION 500\n\n// WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__SHIFT__MAX_INCL is the largest N\n// such that ((10 << N) < (1 << 64)).\n#define WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__SHIFT__MAX_INCL 60\n\n// wuffs_base__private_implementation__high_prec_dec (abbreviated as HPD) is a\n// fixed precision floating point decimal number, augmented with ±infinity\n// values, but it cannot represent NaN (Not a Number).\n//\n// \"High precision\" means that the mantissa holds 500 decimal digits. 500 is\n// WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DIGITS_PRECISION.\n//\n// An HPD isn't for general purpose arithmetic, only for conversions to and\n// from IEEE 754 double-precision floating point, where the largest and\n// smallest positive, finite values are approximately 1.8e+308 and 4.9e-324.\n// HPD exponents above +1023 mean infinity, below -1023 mean zero. Th" +
- "e ±1023\n// bounds are further away from zero than ±(324 + 500), where 500 and 1023 is\n// WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DIGITS_PRECISION and\n// WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DECIMAL_POINT__RANGE.\n//\n// digits[.. num_digits] are the number's digits in big-endian order. The\n// uint8_t values are in the range [0 ..= 9], not ['0' ..= '9'], where e.g. '7'\n// is the ASCII value 0x37.\n//\n// decimal_point is the index (within digits) of the decimal point. It may be\n// negative or be larger than num_digits, in which case the explicit digits are\n// padded with implicit zeroes.\n//\n// For example, if num_digits is 3 and digits is \"\\x07\\x08\\x09\":\n// - A decimal_point of -2 means \".00789\"\n// - A decimal_point of -1 means \".0789\"\n// - A decimal_point of +0 means \".789\"\n// - A decimal_point of +1 means \"7.89\"\n// - A decimal_point of +2 means \"78.9\"\n// - A decimal_point of +3 means \"789.\"\n// - A decimal_point of +4 means \"7890.\"\n// - A decimal_point of +5 means \"78900.\"\n//\n// As above, a" +
- " decimal_point higher than +1023 means that the overall value is\n// infinity, lower than -1023 means zero.\n//\n// negative is a sign bit. An HPD can distinguish positive and negative zero.\n//\n// truncated is whether there are more than\n// WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DIGITS_PRECISION digits, and at\n// least one of those extra digits are non-zero. The existence of long-tail\n// digits can affect rounding.\n//\n// The \"all fields are zero\" value is valid, and represents the number +0.\ntypedef struct {\n uint32_t num_digits;\n int32_t decimal_point;\n bool negative;\n bool truncated;\n uint8_t digits[WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DIGITS_PRECISION];\n} wuffs_base__private_implementation__high_prec_dec;\n\n// wuffs_base__private_implementation__high_prec_dec__trim trims trailing\n// zeroes from the h->digits[.. h->num_digits] slice. They have no benefit,\n// since we explicitly track h->decimal_point.\n//\n// Preconditions:\n// - h is non-NULL.\nstatic inline void //\nwuffs_base__private_implementation_" +
- "_high_prec_dec__trim(\n wuffs_base__private_implementation__high_prec_dec* h) {\n while ((h->num_digits > 0) && (h->digits[h->num_digits - 1] == 0)) {\n h->num_digits--;\n }\n}\n\nstatic wuffs_base__status //\nwuffs_base__private_implementation__high_prec_dec__parse(\n wuffs_base__private_implementation__high_prec_dec* h,\n wuffs_base__slice_u8 s) {\n if (!h) {\n return wuffs_base__make_status(wuffs_base__error__bad_receiver);\n }\n h->num_digits = 0;\n h->decimal_point = 0;\n h->negative = false;\n h->truncated = false;\n\n uint8_t* p = s.ptr;\n uint8_t* q = s.ptr + s.len;\n\n for (; (p < q) && (*p == '_'); p++) {\n }\n if (p >= q) {\n return wuffs_base__make_status(wuffs_base__error__bad_argument);\n }\n\n // Parse sign.\n do {\n if (*p == '+') {\n p++;\n } else if (*p == '-') {\n h->negative = true;\n p++;\n } else {\n break;\n }\n for (; (p < q) && (*p == '_'); p++) {\n }\n } while (0);\n\n // Parse digits.\n uint32_t nd = 0;\n int32_t dp = 0;\n bool saw_digits = false;\n " +
- "bool saw_non_zero_digits = false;\n bool saw_dot = false;\n for (; p < q; p++) {\n if (*p == '_') {\n // No-op.\n\n } else if ((*p == '.') || (*p == ',')) {\n // As per https://en.wikipedia.org/wiki/Decimal_separator, both '.' or\n // ',' are commonly used. We just parse either, regardless of LOCALE.\n if (saw_dot) {\n return wuffs_base__make_status(wuffs_base__error__bad_argument);\n }\n saw_dot = true;\n dp = (int32_t)nd;\n\n } else if ('0' == *p) {\n if (!saw_dot && !saw_non_zero_digits && saw_digits) {\n // We don't allow unnecessary leading zeroes: \"000123\" or \"0644\".\n return wuffs_base__make_status(wuffs_base__error__bad_argument);\n }\n saw_digits = true;\n if (nd == 0) {\n // Track leading zeroes implicitly.\n dp--;\n } else if (nd <\n WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DIGITS_PRECISION) {\n h->digits[nd++] = 0;\n } else {\n // Long-tail zeroes are ignored.\n }\n\n } else if (('" +
- "0' < *p) && (*p <= '9')) {\n if (!saw_dot && !saw_non_zero_digits && saw_digits) {\n // We don't allow unnecessary leading zeroes: \"000123\" or \"0644\".\n return wuffs_base__make_status(wuffs_base__error__bad_argument);\n }\n saw_digits = true;\n saw_non_zero_digits = true;\n if (nd < WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DIGITS_PRECISION) {\n h->digits[nd++] = (uint8_t)(*p - '0');\n } else {\n // Long-tail non-zeroes set the truncated bit.\n h->truncated = true;\n }\n\n } else {\n break;\n }\n }\n\n if (!saw_digits) {\n return wuffs_base__make_status(wuffs_base__error__bad_argument);\n }\n if (!saw_dot) {\n dp = (int32_t)nd;\n }\n\n // Parse exponent.\n if ((p < q) && ((*p == 'E') || (*p == 'e'))) {\n p++;\n for (; (p < q) && (*p == '_'); p++) {\n }\n if (p >= q) {\n return wuffs_base__make_status(wuffs_base__error__bad_argument);\n }\n\n int32_t exp_sign = +1;\n if (*p == '+') {\n p++;\n } else if (*p == '-') {\n " +
- "exp_sign = -1;\n p++;\n }\n\n int32_t exp = 0;\n const int32_t exp_large =\n WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DECIMAL_POINT__RANGE +\n WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DIGITS_PRECISION;\n bool saw_exp_digits = false;\n for (; p < q; p++) {\n if (*p == '_') {\n // No-op.\n } else if (('0' <= *p) && (*p <= '9')) {\n saw_exp_digits = true;\n if (exp < exp_large) {\n exp = (10 * exp) + ((int32_t)(*p - '0'));\n }\n } else {\n break;\n }\n }\n if (!saw_exp_digits) {\n return wuffs_base__make_status(wuffs_base__error__bad_argument);\n }\n dp += exp_sign * exp;\n }\n\n // Finish.\n if (p != q) {\n return wuffs_base__make_status(wuffs_base__error__bad_argument);\n }\n h->num_digits = nd;\n if (nd == 0) {\n h->decimal_point = 0;\n } else if (dp <\n -WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DECIMAL_POINT__RANGE) {\n h->decimal_point =\n -WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DECIMAL_POINT__" +
- "RANGE - 1;\n } else if (dp >\n +WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DECIMAL_POINT__RANGE) {\n h->decimal_point =\n +WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DECIMAL_POINT__RANGE + 1;\n } else {\n h->decimal_point = dp;\n }\n wuffs_base__private_implementation__high_prec_dec__trim(h);\n return wuffs_base__make_status(NULL);\n}\n\n" +
+ "// ---------------- IEEE 754 Floating Point\n\n#define WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DECIMAL_POINT__RANGE 2047\n#define WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DIGITS_PRECISION 800\n\n// WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__SHIFT__MAX_INCL is the largest N\n// such that ((10 << N) < (1 << 64)).\n#define WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__SHIFT__MAX_INCL 60\n\n// wuffs_base__private_implementation__high_prec_dec (abbreviated as HPD) is a\n// fixed precision floating point decimal number, augmented with ±infinity\n// values, but it cannot represent NaN (Not a Number).\n//\n// \"High precision\" means that the mantissa holds 800 decimal digits. 800 is\n// WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DIGITS_PRECISION.\n//\n// An HPD isn't for general purpose arithmetic, only for conversions to and\n// from IEEE 754 double-precision floating point, where the largest and\n// smallest positive, finite values are approximately 1.8e+308 and 4.9e-324.\n// HPD exponents above +2047 mean infinity, below -2047 mean zero. Th" +
+ "e ±2047\n// bounds are further away from zero than ±(324 + 800), where 800 and 2047 is\n// WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DIGITS_PRECISION and\n// WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DECIMAL_POINT__RANGE.\n//\n// digits[.. num_digits] are the number's digits in big-endian order. The\n// uint8_t values are in the range [0 ..= 9], not ['0' ..= '9'], where e.g. '7'\n// is the ASCII value 0x37.\n//\n// decimal_point is the index (within digits) of the decimal point. It may be\n// negative or be larger than num_digits, in which case the explicit digits are\n// padded with implicit zeroes.\n//\n// For example, if num_digits is 3 and digits is \"\\x07\\x08\\x09\":\n// - A decimal_point of -2 means \".00789\"\n// - A decimal_point of -1 means \".0789\"\n// - A decimal_point of +0 means \".789\"\n// - A decimal_point of +1 means \"7.89\"\n// - A decimal_point of +2 means \"78.9\"\n// - A decimal_point of +3 means \"789.\"\n// - A decimal_point of +4 means \"7890.\"\n// - A decimal_point of +5 means \"78900.\"\n//\n// As above, a" +
+ " decimal_point higher than +2047 means that the overall value is\n// infinity, lower than -2047 means zero.\n//\n// negative is a sign bit. An HPD can distinguish positive and negative zero.\n//\n// truncated is whether there are more than\n// WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DIGITS_PRECISION digits, and at\n// least one of those extra digits are non-zero. The existence of long-tail\n// digits can affect rounding.\n//\n// The \"all fields are zero\" value is valid, and represents the number +0.\ntypedef struct {\n uint32_t num_digits;\n int32_t decimal_point;\n bool negative;\n bool truncated;\n uint8_t digits[WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DIGITS_PRECISION];\n} wuffs_base__private_implementation__high_prec_dec;\n\n// wuffs_base__private_implementation__high_prec_dec__trim trims trailing\n// zeroes from the h->digits[.. h->num_digits] slice. They have no benefit,\n// since we explicitly track h->decimal_point.\n//\n// Preconditions:\n// - h is non-NULL.\nstatic inline void //\nwuffs_base__private_implementation_" +
+ "_high_prec_dec__trim(\n wuffs_base__private_implementation__high_prec_dec* h) {\n while ((h->num_digits > 0) && (h->digits[h->num_digits - 1] == 0)) {\n h->num_digits--;\n }\n}\n\n// wuffs_base__private_implementation__high_prec_dec__assign sets h to\n// represent the number x.\n//\n// Preconditions:\n// - h is non-NULL.\nstatic void //\nwuffs_base__private_implementation__high_prec_dec__assign(\n wuffs_base__private_implementation__high_prec_dec* h,\n uint64_t x,\n bool negative) {\n uint32_t n = 0;\n\n // Set h->digits.\n if (x > 0) {\n // Calculate the digits, working right-to-left. After we determine n (how\n // many digits there are), copy from buf to h->digits.\n //\n // UINT64_MAX, 18446744073709551615, is 20 digits long. It can be faster to\n // copy a constant number of bytes than a variable number (20 instead of\n // n). Make buf large enough (and start writing to it from the middle) so\n // that can we always copy 20 bytes: the slice buf[(20-n) .. (40-n)].\n uint8_t buf[40] = {0};" +
+ "\n uint8_t* ptr = &buf[20];\n do {\n uint64_t remaining = x / 10;\n x -= remaining * 10;\n ptr--;\n *ptr = (uint8_t)x;\n n++;\n x = remaining;\n } while (x > 0);\n memcpy(h->digits, ptr, 20);\n }\n\n // Set h's other fields.\n h->num_digits = n;\n h->decimal_point = (int32_t)n;\n h->negative = negative;\n h->truncated = false;\n wuffs_base__private_implementation__high_prec_dec__trim(h);\n}\n\nstatic wuffs_base__status //\nwuffs_base__private_implementation__high_prec_dec__parse(\n wuffs_base__private_implementation__high_prec_dec* h,\n wuffs_base__slice_u8 s) {\n if (!h) {\n return wuffs_base__make_status(wuffs_base__error__bad_receiver);\n }\n h->num_digits = 0;\n h->decimal_point = 0;\n h->negative = false;\n h->truncated = false;\n\n uint8_t* p = s.ptr;\n uint8_t* q = s.ptr + s.len;\n\n for (; (p < q) && (*p == '_'); p++) {\n }\n if (p >= q) {\n return wuffs_base__make_status(wuffs_base__error__bad_argument);\n }\n\n // Parse sign.\n do {\n if (*p == '+') {\n p++;\n " +
+ " } else if (*p == '-') {\n h->negative = true;\n p++;\n } else {\n break;\n }\n for (; (p < q) && (*p == '_'); p++) {\n }\n } while (0);\n\n // Parse digits.\n uint32_t nd = 0;\n int32_t dp = 0;\n bool saw_digits = false;\n bool saw_non_zero_digits = false;\n bool saw_dot = false;\n for (; p < q; p++) {\n if (*p == '_') {\n // No-op.\n\n } else if ((*p == '.') || (*p == ',')) {\n // As per https://en.wikipedia.org/wiki/Decimal_separator, both '.' or\n // ',' are commonly used. We just parse either, regardless of LOCALE.\n if (saw_dot) {\n return wuffs_base__make_status(wuffs_base__error__bad_argument);\n }\n saw_dot = true;\n dp = (int32_t)nd;\n\n } else if ('0' == *p) {\n if (!saw_dot && !saw_non_zero_digits && saw_digits) {\n // We don't allow unnecessary leading zeroes: \"000123\" or \"0644\".\n return wuffs_base__make_status(wuffs_base__error__bad_argument);\n }\n saw_digits = true;\n if (nd == 0) {\n // Track leading " +
+ "zeroes implicitly.\n dp--;\n } else if (nd <\n WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DIGITS_PRECISION) {\n h->digits[nd++] = 0;\n } else {\n // Long-tail zeroes are ignored.\n }\n\n } else if (('0' < *p) && (*p <= '9')) {\n if (!saw_dot && !saw_non_zero_digits && saw_digits) {\n // We don't allow unnecessary leading zeroes: \"000123\" or \"0644\".\n return wuffs_base__make_status(wuffs_base__error__bad_argument);\n }\n saw_digits = true;\n saw_non_zero_digits = true;\n if (nd < WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DIGITS_PRECISION) {\n h->digits[nd++] = (uint8_t)(*p - '0');\n } else {\n // Long-tail non-zeroes set the truncated bit.\n h->truncated = true;\n }\n\n } else {\n break;\n }\n }\n\n if (!saw_digits) {\n return wuffs_base__make_status(wuffs_base__error__bad_argument);\n }\n if (!saw_dot) {\n dp = (int32_t)nd;\n }\n\n // Parse exponent.\n if ((p < q) && ((*p == 'E') || (*p == 'e'))) {\n " +
+ " p++;\n for (; (p < q) && (*p == '_'); p++) {\n }\n if (p >= q) {\n return wuffs_base__make_status(wuffs_base__error__bad_argument);\n }\n\n int32_t exp_sign = +1;\n if (*p == '+') {\n p++;\n } else if (*p == '-') {\n exp_sign = -1;\n p++;\n }\n\n int32_t exp = 0;\n const int32_t exp_large =\n WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DECIMAL_POINT__RANGE +\n WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DIGITS_PRECISION;\n bool saw_exp_digits = false;\n for (; p < q; p++) {\n if (*p == '_') {\n // No-op.\n } else if (('0' <= *p) && (*p <= '9')) {\n saw_exp_digits = true;\n if (exp < exp_large) {\n exp = (10 * exp) + ((int32_t)(*p - '0'));\n }\n } else {\n break;\n }\n }\n if (!saw_exp_digits) {\n return wuffs_base__make_status(wuffs_base__error__bad_argument);\n }\n dp += exp_sign * exp;\n }\n\n // Finish.\n if (p != q) {\n return wuffs_base__make_status(wuffs_base__error__bad_argument);\n }\n h->n" +
+ "um_digits = nd;\n if (nd == 0) {\n h->decimal_point = 0;\n } else if (dp <\n -WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DECIMAL_POINT__RANGE) {\n h->decimal_point =\n -WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DECIMAL_POINT__RANGE - 1;\n } else if (dp >\n +WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DECIMAL_POINT__RANGE) {\n h->decimal_point =\n +WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DECIMAL_POINT__RANGE + 1;\n } else {\n h->decimal_point = dp;\n }\n wuffs_base__private_implementation__high_prec_dec__trim(h);\n return wuffs_base__make_status(NULL);\n}\n\n" +
"" +
"// --------\n\n// The etc__hpd_left_shift and etc__powers_of_5 tables were printed by\n// script/print-hpd-left-shift.go. That script has an optional -comments flag,\n// whose output is not copied here, which prints further detail.\n//\n// These tables are used in\n// wuffs_base__private_implementation__high_prec_dec__lshift_num_new_digits.\n\n// wuffs_base__private_implementation__hpd_left_shift[i] encodes the number of\n// new digits created after multiplying a positive integer by (1 << i): the\n// additional length in the decimal representation. For example, shifting \"234\"\n// by 3 (equivalent to multiplying by 8) will produce \"1872\". Going from a\n// 3-length string to a 4-length string means that 1 new digit was added (and\n// existing digits may have changed).\n//\n// Shifting by i can add either N or N-1 new digits, depending on whether the\n// original positive integer compares >= or < to the i'th power of 5 (as 10\n// equals 2 * 5). Comparison is lexicographic, not numerical.\n//\n// For example, shifting by 4 (i.e. mul" +
"tiplying by 16) can add 1 or 2 new\n// digits, depending on a lexicographic comparison to (5 ** 4), i.e. \"625\":\n// - (\"1\" << 4) is \"16\", which adds 1 new digit.\n// - (\"5678\" << 4) is \"90848\", which adds 1 new digit.\n// - (\"624\" << 4) is \"9984\", which adds 1 new digit.\n// - (\"62498\" << 4) is \"999968\", which adds 1 new digit.\n// - (\"625\" << 4) is \"10000\", which adds 2 new digits.\n// - (\"625001\" << 4) is \"10000016\", which adds 2 new digits.\n// - (\"7008\" << 4) is \"112128\", which adds 2 new digits.\n// - (\"99\" << 4) is \"1584\", which adds 2 new digits.\n//\n// Thus, when i is 4, N is 2 and (5 ** i) is \"625\". This etc__hpd_left_shift\n// array encodes this as:\n// - etc__hpd_left_shift[4] is 0x1006 = (2 << 11) | 0x0006.\n// - etc__hpd_left_shift[5] is 0x1009 = (? << 11) | 0x0009.\n// where the ? isn't relevant for i == 4.\n//\n// The high 5 bits of etc__hpd_left_shift[i] is N, the higher of the two\n// possible number of new digits. The low 11 bits are an offset into the\n//" +
@@ -50,10 +51,21 @@
"" +
"// --------\n\n// wuffs_base__private_implementation__high_prec_dec__rounded_integer returns\n// the integral (non-fractional) part of h, provided that it is 18 or fewer\n// decimal digits. For 19 or more digits, it returns UINT64_MAX. Note that:\n// - (1 << 53) is 9007199254740992, which has 16 decimal digits.\n// - (1 << 56) is 72057594037927936, which has 17 decimal digits.\n// - (1 << 59) is 576460752303423488, which has 18 decimal digits.\n// - (1 << 63) is 9223372036854775808, which has 19 decimal digits.\n// and that IEEE 754 double precision has 52 mantissa bits.\n//\n// That integral part is rounded-to-even: rounding 7.5 or 8.5 both give 8.\n//\n// h's negative bit is ignored: rounding -8.6 returns 9.\n//\n// See below for preconditions.\nstatic uint64_t //\nwuffs_base__private_implementation__high_prec_dec__rounded_integer(\n wuffs_base__private_implementation__high_prec_dec* h) {\n if ((h->num_digits == 0) || (h->decimal_point < 0)) {\n return 0;\n } else if (h->decimal_point > 18) {\n return U" +
"INT64_MAX;\n }\n\n uint32_t dp = (uint32_t)(h->decimal_point);\n uint64_t n = 0;\n uint32_t i = 0;\n for (; i < dp; i++) {\n n = (10 * n) + ((i < h->num_digits) ? h->digits[i] : 0);\n }\n\n bool round_up = false;\n if (dp < h->num_digits) {\n round_up = h->digits[dp] >= 5;\n if ((h->digits[dp] == 5) && (dp + 1 == h->num_digits)) {\n // We are exactly halfway. If we're truncated, round up, otherwise round\n // to even.\n round_up = h->truncated || //\n ((dp > 0) && (1 & h->digits[dp - 1]));\n }\n }\n if (round_up) {\n n++;\n }\n\n return n;\n}\n\n// wuffs_base__private_implementation__high_prec_dec__small_xshift shifts h's\n// number (where 'x' is 'l' or 'r' for left or right) by a small shift value.\n//\n// Preconditions:\n// - h is non-NULL.\n// - h->decimal_point is \"not extreme\".\n// - shift is non-zero.\n// - shift is \"a small shift\".\n//\n// \"Not extreme\" means within\n// ±WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DECIMAL_POINT__RANGE.\n//\n// \"A small shift\" means not more than\n/" +
- "/ WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__SHIFT__MAX_INCL.\n//\n// wuffs_base__private_implementation__high_prec_dec__rounded_integer and\n// wuffs_base__private_implementation__high_prec_dec__lshift_num_new_digits\n// have the same preconditions.\n\nstatic void //\nwuffs_base__private_implementation__high_prec_dec__small_lshift(\n wuffs_base__private_implementation__high_prec_dec* h,\n uint32_t shift) {\n if (h->num_digits == 0) {\n return;\n }\n uint32_t num_new_digits =\n wuffs_base__private_implementation__high_prec_dec__lshift_num_new_digits(\n h, shift);\n uint32_t rx = h->num_digits - 1; // Read index.\n uint32_t wx = h->num_digits - 1 + num_new_digits; // Write index.\n uint64_t n = 0;\n\n // Repeat: pick up a digit, put down a digit, right to left.\n while (((int32_t)rx) >= 0) {\n n += ((uint64_t)(h->digits[rx])) << shift;\n uint64_t quo = n / 10;\n uint64_t rem = n - (10 * quo);\n if (wx < WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DIGITS_PRECISION) {\n h->d" +
- "igits[wx] = (uint8_t)rem;\n } else if (rem > 0) {\n h->truncated = true;\n }\n n = quo;\n wx--;\n rx--;\n }\n\n // Put down leading digits, right to left.\n while (n > 0) {\n uint64_t quo = n / 10;\n uint64_t rem = n - (10 * quo);\n if (wx < WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DIGITS_PRECISION) {\n h->digits[wx] = (uint8_t)rem;\n } else if (rem > 0) {\n h->truncated = true;\n }\n n = quo;\n wx--;\n }\n\n // Finish.\n h->num_digits += num_new_digits;\n if (h->num_digits >\n WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DIGITS_PRECISION) {\n h->num_digits = WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DIGITS_PRECISION;\n }\n h->decimal_point += (int32_t)num_new_digits;\n wuffs_base__private_implementation__high_prec_dec__trim(h);\n}\n\nstatic void //\nwuffs_base__private_implementation__high_prec_dec__small_rshift(\n wuffs_base__private_implementation__high_prec_dec* h,\n uint32_t shift) {\n uint32_t rx = 0; // Read index.\n uint32_t wx = 0; // Write index.\n uint64_t n =" +
- " 0;\n\n // Pick up enough leading digits to cover the first shift.\n while ((n >> shift) == 0) {\n if (rx < h->num_digits) {\n // Read a digit.\n n = (10 * n) + h->digits[rx++];\n } else if (n == 0) {\n // h's number used to be zero and remains zero.\n return;\n } else {\n // Read sufficient implicit trailing zeroes.\n while ((n >> shift) == 0) {\n n = 10 * n;\n rx++;\n }\n break;\n }\n }\n h->decimal_point -= ((int32_t)(rx - 1));\n if (h->decimal_point <\n -WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DECIMAL_POINT__RANGE) {\n // After the shift, h's number is effectively zero.\n h->num_digits = 0;\n h->decimal_point = 0;\n h->negative = false;\n h->truncated = false;\n return;\n }\n\n // Repeat: pick up a digit, put down a digit, left to right.\n uint64_t mask = (((uint64_t)(1)) << shift) - 1;\n while (rx < h->num_digits) {\n uint8_t new_digit = ((uint8_t)(n >> shift));\n n = (10 * (n & mask)) + h->digits[rx++];\n h->digits[wx++] = new_digi" +
- "t;\n }\n\n // Put down trailing digits, left to right.\n while (n > 0) {\n uint8_t new_digit = ((uint8_t)(n >> shift));\n n = 10 * (n & mask);\n if (wx < WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DIGITS_PRECISION) {\n h->digits[wx++] = new_digit;\n } else if (new_digit > 0) {\n h->truncated = true;\n }\n }\n\n // Finish.\n h->num_digits = wx;\n wuffs_base__private_implementation__high_prec_dec__trim(h);\n}\n\n" +
+ "/ WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__SHIFT__MAX_INCL.\n//\n// wuffs_base__private_implementation__high_prec_dec__rounded_integer and\n// wuffs_base__private_implementation__high_prec_dec__lshift_num_new_digits\n// have the same preconditions.\n//\n// wuffs_base__private_implementation__high_prec_dec__lshift keeps the first\n// two preconditions but not the last two. Its shift argument is signed and\n// does not need to be \"small\": zero is a no-op, positive means left shift and\n// negative means right shift.\n\nstatic void //\nwuffs_base__private_implementation__high_prec_dec__small_lshift(\n wuffs_base__private_implementation__high_prec_dec* h,\n uint32_t shift) {\n if (h->num_digits == 0) {\n return;\n }\n uint32_t num_new_digits =\n wuffs_base__private_implementation__high_prec_dec__lshift_num_new_digits(\n h, shift);\n uint32_t rx = h->num_digits - 1; // Read index.\n uint32_t wx = h->num_digits - 1 + num_new_digits; // Write index.\n uint64_t n = 0;\n\n // Repeat: pick up " +
+ "a digit, put down a digit, right to left.\n while (((int32_t)rx) >= 0) {\n n += ((uint64_t)(h->digits[rx])) << shift;\n uint64_t quo = n / 10;\n uint64_t rem = n - (10 * quo);\n if (wx < WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DIGITS_PRECISION) {\n h->digits[wx] = (uint8_t)rem;\n } else if (rem > 0) {\n h->truncated = true;\n }\n n = quo;\n wx--;\n rx--;\n }\n\n // Put down leading digits, right to left.\n while (n > 0) {\n uint64_t quo = n / 10;\n uint64_t rem = n - (10 * quo);\n if (wx < WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DIGITS_PRECISION) {\n h->digits[wx] = (uint8_t)rem;\n } else if (rem > 0) {\n h->truncated = true;\n }\n n = quo;\n wx--;\n }\n\n // Finish.\n h->num_digits += num_new_digits;\n if (h->num_digits >\n WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DIGITS_PRECISION) {\n h->num_digits = WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DIGITS_PRECISION;\n }\n h->decimal_point += (int32_t)num_new_digits;\n wuffs_base__private_implementation__high_pre" +
+ "c_dec__trim(h);\n}\n\nstatic void //\nwuffs_base__private_implementation__high_prec_dec__small_rshift(\n wuffs_base__private_implementation__high_prec_dec* h,\n uint32_t shift) {\n uint32_t rx = 0; // Read index.\n uint32_t wx = 0; // Write index.\n uint64_t n = 0;\n\n // Pick up enough leading digits to cover the first shift.\n while ((n >> shift) == 0) {\n if (rx < h->num_digits) {\n // Read a digit.\n n = (10 * n) + h->digits[rx++];\n } else if (n == 0) {\n // h's number used to be zero and remains zero.\n return;\n } else {\n // Read sufficient implicit trailing zeroes.\n while ((n >> shift) == 0) {\n n = 10 * n;\n rx++;\n }\n break;\n }\n }\n h->decimal_point -= ((int32_t)(rx - 1));\n if (h->decimal_point <\n -WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DECIMAL_POINT__RANGE) {\n // After the shift, h's number is effectively zero.\n h->num_digits = 0;\n h->decimal_point = 0;\n h->negative = false;\n h->truncated = false;\n return;\n }\n\n " +
+ "// Repeat: pick up a digit, put down a digit, left to right.\n uint64_t mask = (((uint64_t)(1)) << shift) - 1;\n while (rx < h->num_digits) {\n uint8_t new_digit = ((uint8_t)(n >> shift));\n n = (10 * (n & mask)) + h->digits[rx++];\n h->digits[wx++] = new_digit;\n }\n\n // Put down trailing digits, left to right.\n while (n > 0) {\n uint8_t new_digit = ((uint8_t)(n >> shift));\n n = 10 * (n & mask);\n if (wx < WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DIGITS_PRECISION) {\n h->digits[wx++] = new_digit;\n } else if (new_digit > 0) {\n h->truncated = true;\n }\n }\n\n // Finish.\n h->num_digits = wx;\n wuffs_base__private_implementation__high_prec_dec__trim(h);\n}\n\nstatic void //\nwuffs_base__private_implementation__high_prec_dec__lshift(\n wuffs_base__private_implementation__high_prec_dec* h,\n int32_t shift) {\n if (shift > 0) {\n while (shift > +WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__SHIFT__MAX_INCL) {\n wuffs_base__private_implementation__high_prec_dec__small_lshift(\n " +
+ " h, WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__SHIFT__MAX_INCL);\n shift -= WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__SHIFT__MAX_INCL;\n }\n wuffs_base__private_implementation__high_prec_dec__small_lshift(\n h, ((uint32_t)(+shift)));\n } else if (shift < 0) {\n while (shift < -WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__SHIFT__MAX_INCL) {\n wuffs_base__private_implementation__high_prec_dec__small_rshift(\n h, WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__SHIFT__MAX_INCL);\n shift += WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__SHIFT__MAX_INCL;\n }\n wuffs_base__private_implementation__high_prec_dec__small_rshift(\n h, ((uint32_t)(-shift)));\n }\n}\n\n" +
+ "" +
+ "// --------\n\n// wuffs_base__private_implementation__high_prec_dec__round_etc rounds h's\n// number. For those functions that take an n argument, rounding produces at\n// most n digits (which is not necessarily at most n decimal places). Negative\n// n values are ignored, as well as any n greater than or equal to h's number\n// of digits. The etc__round_just_enough function implicitly chooses an n to\n// implement WUFFS_BASE__RENDER_NUMBER_FXX__JUST_ENOUGH_PRECISION.\n//\n// Preconditions:\n// - h is non-NULL.\n// - h->decimal_point is \"not extreme\".\n//\n// \"Not extreme\" means within\n// ±WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DECIMAL_POINT__RANGE.\n\nstatic void //\nwuffs_base__private_implementation__high_prec_dec__round_down(\n wuffs_base__private_implementation__high_prec_dec* h,\n int32_t n) {\n if ((n < 0) || (h->num_digits <= (uint32_t)n)) {\n return;\n }\n h->num_digits = (uint32_t)(n);\n wuffs_base__private_implementation__high_prec_dec__trim(h);\n}\n\nstatic void //\nwuffs_base__private_implementation__hi" +
+ "gh_prec_dec__round_up(\n wuffs_base__private_implementation__high_prec_dec* h,\n int32_t n) {\n if ((n < 0) || (h->num_digits <= (uint32_t)n)) {\n return;\n }\n\n for (n--; n >= 0; n--) {\n if (h->digits[n] < 9) {\n h->digits[n]++;\n h->num_digits = (uint32_t)(n + 1);\n return;\n }\n }\n\n // The number is all 9s. Change to a single 1 and adjust the decimal point.\n h->digits[0] = 1;\n h->num_digits = 1;\n h->decimal_point++;\n}\n\nstatic void //\nwuffs_base__private_implementation__high_prec_dec__round_nearest(\n wuffs_base__private_implementation__high_prec_dec* h,\n int32_t n) {\n if ((n < 0) || (h->num_digits <= (uint32_t)n)) {\n return;\n }\n bool up = h->digits[n] >= 5;\n if ((h->digits[n] == 5) && ((n + 1) == ((int32_t)(h->num_digits)))) {\n up = h->truncated || //\n ((n > 0) && ((h->digits[n - 1] & 1) != 0));\n }\n\n if (up) {\n wuffs_base__private_implementation__high_prec_dec__round_up(h, n);\n } else {\n wuffs_base__private_implementation__high_prec_dec__round_do" +
+ "wn(h, n);\n }\n}\n\nstatic void //\nwuffs_base__private_implementation__high_prec_dec__round_just_enough(\n wuffs_base__private_implementation__high_prec_dec* h,\n int32_t exp2,\n uint64_t mantissa) {\n // The magic numbers 52 and 53 in this function are because IEEE 754 double\n // precision has 52 mantissa bits.\n //\n // Let f be the floating point number represented by exp2 and mantissa (and\n // also the number in h): the number (mantissa * (2 ** (exp2 - 52))).\n //\n // If f is zero, we can return early.\n if (mantissa == 0) {\n return;\n }\n\n // The smallest normal f has an exp2 of -1022 and a mantissa of (1 << 52).\n // Subnormal numbers have the same exp2 but a smaller mantissa.\n static const int32_t min_incl_normal_exp2 = -1022;\n static const uint64_t min_incl_normal_mantissa = 0x0010000000000000ul;\n\n // Compute lower and upper bounds such that any number between them (possibly\n // inclusive) will round to f. First, the lower bound. Our number f is:\n // ((mantissa + 0) * (2 ** ( " +
+ " exp2 - 52)))\n //\n // The next lowest floating point number is:\n // ((mantissa - 1) * (2 ** ( exp2 - 52)))\n // unless (mantissa - 1) drops the (1 << 52) bit and exp2 is not the\n // min_incl_normal_exp2. Either way, call it:\n // ((l_mantissa) * (2 ** (l_exp2 - 52)))\n //\n // The lower bound is halfway between them (noting that 52 became 53):\n // (((2 * l_mantissa) + 1) * (2 ** (l_exp2 - 53)))\n int32_t l_exp2 = exp2;\n uint64_t l_mantissa = mantissa - 1;\n if ((exp2 > min_incl_normal_exp2) && (mantissa <= min_incl_normal_mantissa)) {\n l_exp2 = exp2 - 1;\n l_mantissa = (2 * mantissa) - 1;\n }\n wuffs_base__private_implementation__high_prec_dec lower;\n wuffs_base__private_implementation__high_prec_dec__assign(\n &lower, (2 * l_mantissa) + 1, false);\n wuffs_base__private_implementation__high_prec_dec__lshift(&lower,\n l_exp2 - 53);\n\n // Next, the upper bound. Our number f is:\n // ((mantissa + 0) * (2 **" +
+ " (exp2 - 52)))\n //\n // The next highest floating point number is:\n // ((mantissa + 1) * (2 ** (exp2 - 52)))\n //\n // The upper bound is halfway between them (noting that 52 became 53):\n // (((2 * mantissa) + 1) * (2 ** (exp2 - 53)))\n wuffs_base__private_implementation__high_prec_dec upper;\n wuffs_base__private_implementation__high_prec_dec__assign(\n &upper, (2 * mantissa) + 1, false);\n wuffs_base__private_implementation__high_prec_dec__lshift(&upper, exp2 - 53);\n\n // The lower and upper bounds are possible outputs only if the original\n // mantissa is even, so that IEEE round-to-even would round to the original\n // mantissa and not its neighbors.\n bool inclusive = (mantissa & 1) == 0;\n\n // As we walk the digits, we want to know whether rounding up would fall\n // within the upper bound. This is tracked by upper_delta:\n // - When -1, the digits of h and upper are the same so far.\n // - When +0, we saw a difference of 1 between h and upper on a previous\n // digit and subsequen" +
+ "tly only 9s for h and 0s for upper. Thus, rounding\n // up may fall outside of the bound if !inclusive.\n // - When +1, the difference is greater than 1 and we know that rounding up\n // falls within the bound.\n //\n // This is a state machine with three states. The numerical value for each\n // state (-1, +0 or +1) isn't important, other than their order.\n int upper_delta = -1;\n\n // We can now figure out the shortest number of digits required. Walk the\n // digits until h has distinguished itself from lower or upper.\n //\n // The zi and zd variables are indexes and digits, for z in l (lower), h (the\n // number) and u (upper).\n //\n // The lower, h and upper numbers may have their decimal points at different\n // places. In this case, upper is the longest, so we iterate ui starting from\n // 0 and iterate li and hi starting from either 0 or -1.\n int32_t ui = 0;\n for (;; ui++) {\n // Calculate hd, the middle number's digit.\n int32_t hi = ui - upper.decimal_point + h->decimal_point;\n if (" +
+ "hi >= ((int32_t)(h->num_digits))) {\n break;\n }\n uint8_t hd = (((uint32_t)hi) < h->num_digits) ? h->digits[hi] : 0;\n\n // Calculate ld, the lower bound's digit.\n int32_t li = ui - upper.decimal_point + lower.decimal_point;\n uint8_t ld = (((uint32_t)li) < lower.num_digits) ? lower.digits[li] : 0;\n\n // We can round down (truncate) if lower has a different digit than h or if\n // lower is inclusive and is exactly the result of rounding down (i.e. we\n // have reached the final digit of lower).\n bool can_round_down =\n (ld != hd) || //\n (inclusive && ((li + 1) == ((int32_t)(lower.num_digits))));\n\n // Calculate ud, the upper bound's digit, and update upper_delta.\n uint8_t ud = (((uint32_t)ui) < upper.num_digits) ? upper.digits[ui] : 0;\n if (upper_delta < 0) {\n if ((hd + 1) < ud) {\n // For example:\n // h = 12345???\n // upper = 12347???\n upper_delta = +1;\n } else if (hd != ud) {\n // For example:\n // h = 123" +
+ "45???\n // upper = 12346???\n upper_delta = +0;\n }\n } else if (upper_delta == 0) {\n if ((hd != 9) || (ud != 0)) {\n // For example:\n // h = 1234598?\n // upper = 1234600?\n upper_delta = +1;\n }\n }\n\n // We can round up if upper has a different digit than h and either upper\n // is inclusive or upper is bigger than the result of rounding up.\n bool can_round_up =\n (upper_delta > 0) || //\n ((upper_delta == 0) && //\n (inclusive || ((ui + 1) < ((int32_t)(upper.num_digits)))));\n\n // If we can round either way, round to nearest. If we can round only one\n // way, do it. If we can't round, continue the loop.\n if (can_round_down) {\n if (can_round_up) {\n wuffs_base__private_implementation__high_prec_dec__round_nearest(\n h, hi + 1);\n return;\n } else {\n wuffs_base__private_implementation__high_prec_dec__round_down(h,\n " +
+ " hi + 1);\n return;\n }\n } else {\n if (can_round_up) {\n wuffs_base__private_implementation__high_prec_dec__round_up(h, hi + 1);\n return;\n }\n }\n }\n}\n\n" +
"" +
"// --------\n\n// The wuffs_base__private_implementation__etc_powers_of_10 tables were printed\n// by script/print-mpb-powers-of-10.go. That script has an optional -comments\n// flag, whose output is not copied here, which prints further detail.\n//\n// These tables are used in\n// wuffs_base__private_implementation__medium_prec_bin__assign_from_hpd.\n\n// wuffs_base__private_implementation__big_powers_of_10 contains approximations\n// to the powers of 10, ranging from 1e-348 to 1e+340, with the exponent\n// stepping by 8: -348, -340, -332, ..., -12, -4, +4, +12, ..., +340. Each step\n// consists of three uint32_t elements. There are 87 triples, 87 * 3 = 261.\n//\n// For example, the third approximation, for 1e-332, consists of the uint32_t\n// triple (0x3055AC76, 0x8B16FB20, 0xFFFFFB72). The first two of that triple\n// are a little-endian uint64_t value: 0x8B16FB203055AC76. The last one is an\n// int32_t value: -1166. Together, they represent the approximation:\n// 1e-332 ≈ 0x8B16FB203055AC76 * (2 ** -1166)\n// Similarly," +
" the (0x00000000, 0x9C400000, 0xFFFFFFCE) uint32_t triple means:\n// 1e+4 ≈ 0x9C40000000000000 * (2 ** -50) // This approx'n is exact.\n// Similarly, the (0xD4C4FB27, 0xED63A231, 0x000000A2) uint32_t triple means:\n// 1e+68 ≈ 0xED63A231D4C4FB27 * (2 ** 162)\nstatic const uint32_t\n wuffs_base__private_implementation__big_powers_of_10[261] = {\n 0x081C0288, 0xFA8FD5A0, 0xFFFFFB3C, 0xA23EBF76, 0xBAAEE17F, 0xFFFFFB57,\n 0x3055AC76, 0x8B16FB20, 0xFFFFFB72, 0x5DCE35EA, 0xCF42894A, 0xFFFFFB8C,\n 0x55653B2D, 0x9A6BB0AA, 0xFFFFFBA7, 0x3D1A45DF, 0xE61ACF03, 0xFFFFFBC1,\n 0xC79AC6CA, 0xAB70FE17, 0xFFFFFBDC, 0xBEBCDC4F, 0xFF77B1FC, 0xFFFFFBF6,\n 0x416BD60C, 0xBE5691EF, 0xFFFFFC11, 0x907FFC3C, 0x8DD01FAD, 0xFFFFFC2C,\n 0x31559A83, 0xD3515C28, 0xFFFFFC46, 0xADA6C9B5, 0x9D71AC8F, 0xFFFFFC61,\n 0x23EE8BCB, 0xEA9C2277, 0xFFFFFC7B, 0x4078536D, 0xAECC4991, 0xFFFFFC96,\n 0x5DB6CE57, 0x823C1279, 0xFFFFFCB1, 0x4DFB5637, 0xC2109436, 0xFFFFFCCB,\n 0x3848984F, 0x909" +
@@ -84,7 +96,17 @@
".decimal_point);\n uint32_t shift =\n (n < num_powers)\n ? powers[n]\n : WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__SHIFT__MAX_INCL;\n\n wuffs_base__private_implementation__high_prec_dec__small_rshift(&h,\n shift);\n if (h.decimal_point <\n -WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DECIMAL_POINT__RANGE) {\n goto zero;\n }\n exp2 += (int32_t)shift;\n }\n // ...then we shift left, putting us in [½ .. 1].\n while (h.decimal_point <= 0) {\n uint32_t shift;\n if (h.decimal_point == 0) {\n if (h.digits[0] >= 5) {\n break;\n }\n shift = (h.digits[0] <= 2) ? 2 : 1;\n } else {\n uint32_t n = (uint32_t)(-h.decimal_point);\n shift = (n < num_powers)\n ? powers[n]\n : WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__SHIFT__MAX_INCL;\n }\n\n wuffs_base__private_implementation__high_prec_dec__small_lshif" +
"t(&h,\n shift);\n if (h.decimal_point >\n +WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DECIMAL_POINT__RANGE) {\n goto infinity;\n }\n exp2 -= (int32_t)shift;\n }\n\n // We're in the range [½ .. 1] but f64 uses [1 .. 2].\n exp2--;\n\n // The minimum normal exponent is (f64_bias + 1).\n while ((f64_bias + 1) > exp2) {\n uint32_t n = (uint32_t)((f64_bias + 1) - exp2);\n if (n > WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__SHIFT__MAX_INCL) {\n n = WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__SHIFT__MAX_INCL;\n }\n wuffs_base__private_implementation__high_prec_dec__small_rshift(&h, n);\n exp2 += (int32_t)n;\n }\n\n // Check for overflow.\n if ((exp2 - f64_bias) >= 0x07FF) { // (1 << 11) - 1.\n goto infinity;\n }\n\n // Extract 53 bits for the mantissa (in base-2).\n wuffs_base__private_implementation__high_prec_dec__small_lshift(&h, 53);\n uint64_t man2 =\n wuffs_base__privat" +
"e_implementation__high_prec_dec__rounded_integer(&h);\n\n // Rounding might have added one bit. If so, shift and re-check overflow.\n if ((man2 >> 53) != 0) {\n man2 >>= 1;\n exp2++;\n if ((exp2 - f64_bias) >= 0x07FF) { // (1 << 11) - 1.\n goto infinity;\n }\n }\n\n // Handle subnormal numbers.\n if ((man2 >> 52) == 0) {\n exp2 = f64_bias;\n }\n\n // Pack the bits and return.\n uint64_t exp2_bits =\n (uint64_t)((exp2 - f64_bias) & 0x07FF); // (1 << 11) - 1.\n uint64_t bits = (man2 & 0x000FFFFFFFFFFFFF) | // (1 << 52) - 1.\n (exp2_bits << 52) | //\n (h.negative ? 0x8000000000000000 : 0); // (1 << 63).\n\n wuffs_base__result_f64 ret;\n ret.status.repr = NULL;\n ret.value = wuffs_base__ieee_754_bit_representation__to_f64(bits);\n return ret;\n } while (0);\n\nzero:\n do {\n uint64_t bits = h.negative ? 0x8000000000000000 : 0;\n\n wuffs_base__result_f64 ret;\n ret.status.repr = " +
- "NULL;\n ret.value = wuffs_base__ieee_754_bit_representation__to_f64(bits);\n return ret;\n } while (0);\n\ninfinity:\n do {\n uint64_t bits = h.negative ? 0xFFF0000000000000 : 0x7FF0000000000000;\n\n wuffs_base__result_f64 ret;\n ret.status.repr = NULL;\n ret.value = wuffs_base__ieee_754_bit_representation__to_f64(bits);\n return ret;\n } while (0);\n}\n" +
+ "NULL;\n ret.value = wuffs_base__ieee_754_bit_representation__to_f64(bits);\n return ret;\n } while (0);\n\ninfinity:\n do {\n uint64_t bits = h.negative ? 0xFFF0000000000000 : 0x7FF0000000000000;\n\n wuffs_base__result_f64 ret;\n ret.status.repr = NULL;\n ret.value = wuffs_base__ieee_754_bit_representation__to_f64(bits);\n return ret;\n } while (0);\n}\n\n" +
+ "" +
+ "// --------\n\nstatic inline size_t //\nwuffs_base__private_implementation__render_inf(wuffs_base__slice_u8 dst,\n bool neg,\n uint32_t options) {\n if (neg) {\n if (dst.len < 4) {\n return 0;\n }\n wuffs_base__store_u32le__no_bounds_check(dst.ptr, 0x666E492D); // '-Inf'le.\n return 4;\n }\n\n if (options & WUFFS_BASE__RENDER_NUMBER_XXX__LEADING_PLUS_SIGN) {\n if (dst.len < 4) {\n return 0;\n }\n wuffs_base__store_u32le__no_bounds_check(dst.ptr, 0x666E492B); // '+Inf'le.\n return 4;\n }\n\n if (dst.len < 3) {\n return 0;\n }\n wuffs_base__store_u24le__no_bounds_check(dst.ptr, 0x666E49); // 'Inf'le.\n return 3;\n}\n\nstatic inline size_t //\nwuffs_base__private_implementation__render_nan(wuffs_base__slice_u8 dst) {\n if (dst.len < 3) {\n return 0;\n }\n wuffs_base__store_u24le__no_bounds_check(dst.ptr, 0x4E614E); // 'NaN'le.\n return 3;\n}\n\nstatic size_t //\nwuffs_base__private_implementation__high" +
+ "_prec_dec__render_exponent_absent(\n wuffs_base__slice_u8 dst,\n wuffs_base__private_implementation__high_prec_dec* h,\n uint32_t precision,\n uint32_t options) {\n size_t n = (h->negative ||\n (options & WUFFS_BASE__RENDER_NUMBER_XXX__LEADING_PLUS_SIGN))\n ? 1\n : 0;\n if (h->decimal_point <= 0) {\n n += 1;\n } else {\n n += (size_t)(h->decimal_point);\n }\n if (precision > 0) {\n n += precision + 1; // +1 for the '.'.\n }\n\n // Don't modify dst if the formatted number won't fit.\n if (n > dst.len) {\n return 0;\n }\n\n // Align-left or align-right.\n uint8_t* ptr = (options & WUFFS_BASE__RENDER_NUMBER_XXX__ALIGN_RIGHT)\n ? &dst.ptr[dst.len - n]\n : &dst.ptr[0];\n\n // Leading \"±\".\n if (h->negative) {\n *ptr++ = '-';\n } else if (options & WUFFS_BASE__RENDER_NUMBER_XXX__LEADING_PLUS_SIGN) {\n *ptr++ = '+';\n }\n\n // Integral digits.\n if (h->decimal_point <= 0) {\n *ptr++ = '0';\n } else {\n uint32_t m =\n" +
+ " wuffs_base__u32__min(h->num_digits, (uint32_t)(h->decimal_point));\n uint32_t i = 0;\n for (; i < m; i++) {\n *ptr++ = (uint8_t)('0' | h->digits[i]);\n }\n for (; i < (uint32_t)(h->decimal_point); i++) {\n *ptr++ = '0';\n }\n }\n\n // Separator and then fractional digits.\n if (precision > 0) {\n *ptr++ =\n (options & WUFFS_BASE__RENDER_NUMBER_FXX__DECIMAL_SEPARATOR_IS_A_COMMA)\n ? ','\n : '.';\n uint32_t i = 0;\n for (; i < precision; i++) {\n uint32_t j = ((uint32_t)(h->decimal_point)) + i;\n *ptr++ = (uint8_t)('0' | ((j < h->num_digits) ? h->digits[j] : 0));\n }\n }\n\n return n;\n}\n\nstatic size_t //\nwuffs_base__private_implementation__high_prec_dec__render_exponent_present(\n wuffs_base__slice_u8 dst,\n wuffs_base__private_implementation__high_prec_dec* h,\n uint32_t precision,\n uint32_t options) {\n int32_t exp = 0;\n if (h->num_digits > 0) {\n exp = h->decimal_point - 1;\n }\n bool negative_exp = exp < 0;\n if (negative_exp) {\n" +
+ " exp = -exp;\n }\n\n size_t n = (h->negative ||\n (options & WUFFS_BASE__RENDER_NUMBER_XXX__LEADING_PLUS_SIGN))\n ? 4\n : 3; // Mininum 3 bytes: first digit and then \"e±\".\n if (precision > 0) {\n n += precision + 1; // +1 for the '.'.\n }\n n += (exp < 100) ? 2 : 3;\n\n // Don't modify dst if the formatted number won't fit.\n if (n > dst.len) {\n return 0;\n }\n\n // Align-left or align-right.\n uint8_t* ptr = (options & WUFFS_BASE__RENDER_NUMBER_XXX__ALIGN_RIGHT)\n ? &dst.ptr[dst.len - n]\n : &dst.ptr[0];\n\n // Leading \"±\".\n if (h->negative) {\n *ptr++ = '-';\n } else if (options & WUFFS_BASE__RENDER_NUMBER_XXX__LEADING_PLUS_SIGN) {\n *ptr++ = '+';\n }\n\n // Integral digit.\n if (h->num_digits > 0) {\n *ptr++ = (uint8_t)('0' | h->digits[0]);\n } else {\n *ptr++ = '0';\n }\n\n // Separator and then fractional digits.\n if (precision > 0) {\n *ptr++ =\n (options & WUFFS_BASE__RENDER_NUMBER_FXX__DECIMAL_SEPA" +
+ "RATOR_IS_A_COMMA)\n ? ','\n : '.';\n uint32_t i = 1;\n uint32_t j = wuffs_base__u32__min(h->num_digits, precision + 1);\n for (; i < j; i++) {\n *ptr++ = (uint8_t)('0' | h->digits[i]);\n }\n for (; i <= precision; i++) {\n *ptr++ = '0';\n }\n }\n\n // Exponent: \"e±\" and then 2 or 3 digits.\n *ptr++ = 'e';\n *ptr++ = negative_exp ? '-' : '+';\n if (exp < 10) {\n *ptr++ = '0';\n *ptr++ = (uint8_t)('0' | exp);\n } else if (exp < 100) {\n *ptr++ = (uint8_t)('0' | (exp / 10));\n *ptr++ = (uint8_t)('0' | (exp % 10));\n } else {\n int32_t e = exp / 100;\n exp -= e * 100;\n *ptr++ = (uint8_t)('0' | e);\n *ptr++ = (uint8_t)('0' | (exp / 10));\n *ptr++ = (uint8_t)('0' | (exp % 10));\n }\n\n return n;\n}\n\nWUFFS_BASE__MAYBE_STATIC size_t //\nwuffs_base__render_number_f64(wuffs_base__slice_u8 dst,\n double x,\n uint32_t precision,\n uint32_t options) {\n // Decompose x (64 bits) into " +
+ "negativity (1 bit), base-2 exponent (11 bits\n // with a -1023 bias) and mantissa (52 bits).\n uint64_t bits = wuffs_base__ieee_754_bit_representation__from_f64(x);\n bool neg = (bits >> 63) != 0;\n int32_t exp2 = ((int32_t)(bits >> 52)) & 0x7FF;\n uint64_t man = bits & 0x000FFFFFFFFFFFFFul;\n\n // Apply the exponent bias and set the implicit top bit of the mantissa,\n // unless x is subnormal. Also take care of Inf and NaN.\n if (exp2 == 0x7FF) {\n if (man != 0) {\n return wuffs_base__private_implementation__render_nan(dst);\n }\n return wuffs_base__private_implementation__render_inf(dst, neg, options);\n } else if (exp2 == 0) {\n exp2 = -1022;\n } else {\n exp2 -= 1023;\n man |= 0x0010000000000000ul;\n }\n\n // Ensure that precision isn't too large.\n if (precision > 4095) {\n precision = 4095;\n }\n\n // Convert from the (neg, exp2, man) tuple to an HPD.\n wuffs_base__private_implementation__high_prec_dec h;\n wuffs_base__private_implementation__high_prec_dec__assign(&h, man, neg);\n if (h.n" +
+ "um_digits > 0) {\n wuffs_base__private_implementation__high_prec_dec__lshift(\n &h, exp2 - 52); // 52 mantissa bits.\n }\n\n // Handle the \"%e\" and \"%f\" formats.\n switch (options & (WUFFS_BASE__RENDER_NUMBER_FXX__EXPONENT_ABSENT |\n WUFFS_BASE__RENDER_NUMBER_FXX__EXPONENT_PRESENT)) {\n case WUFFS_BASE__RENDER_NUMBER_FXX__EXPONENT_ABSENT: // The \"%\"f\" format.\n if (options & WUFFS_BASE__RENDER_NUMBER_FXX__JUST_ENOUGH_PRECISION) {\n wuffs_base__private_implementation__high_prec_dec__round_just_enough(\n &h, exp2, man);\n int32_t p = ((int32_t)(h.num_digits)) - h.decimal_point;\n precision = ((uint32_t)(wuffs_base__i32__max(0, p)));\n } else {\n wuffs_base__private_implementation__high_prec_dec__round_nearest(\n &h, ((int32_t)precision) + h.decimal_point);\n }\n return wuffs_base__private_implementation__high_prec_dec__render_exponent_absent(\n dst, &h, precision, options);\n\n case WUFFS_BASE__RENDER_NUMBER_FXX__" +
+ "EXPONENT_PRESENT: // The \"%e\" format.\n if (options & WUFFS_BASE__RENDER_NUMBER_FXX__JUST_ENOUGH_PRECISION) {\n wuffs_base__private_implementation__high_prec_dec__round_just_enough(\n &h, exp2, man);\n precision = (h.num_digits > 0) ? (h.num_digits - 1) : 0;\n } else {\n wuffs_base__private_implementation__high_prec_dec__round_nearest(\n &h, ((int32_t)precision) + 1);\n }\n return wuffs_base__private_implementation__high_prec_dec__render_exponent_present(\n dst, &h, precision, options);\n }\n\n // We have the \"%g\" format and so precision means the number of significant\n // digits, not the number of digits after the decimal separator. Perform\n // rounding and determine whether to use \"%e\" or \"%f\".\n int32_t e_threshold = 0;\n if (options & WUFFS_BASE__RENDER_NUMBER_FXX__JUST_ENOUGH_PRECISION) {\n wuffs_base__private_implementation__high_prec_dec__round_just_enough(\n &h, exp2, man);\n precision = h.num_digits;\n e_threshold = 6;\n } el" +
+ "se {\n if (precision == 0) {\n precision = 1;\n }\n wuffs_base__private_implementation__high_prec_dec__round_nearest(\n &h, ((int32_t)precision));\n e_threshold = ((int32_t)precision);\n int32_t nd = ((int32_t)(h.num_digits));\n if ((e_threshold > nd) && (nd >= h.decimal_point)) {\n e_threshold = nd;\n }\n }\n\n // Use the \"%e\" format if the exponent is large.\n int32_t e = h.decimal_point - 1;\n if ((e < -4) || (e_threshold <= e)) {\n uint32_t p = wuffs_base__u32__min(precision, h.num_digits);\n return wuffs_base__private_implementation__high_prec_dec__render_exponent_present(\n dst, &h, (p > 0) ? (p - 1) : 0, options);\n }\n\n // Use the \"%f\" format otherwise.\n int32_t p = ((int32_t)precision);\n if (p > h.decimal_point) {\n p = ((int32_t)(h.num_digits));\n }\n precision = ((uint32_t)(wuffs_base__i32__max(0, p - h.decimal_point)));\n return wuffs_base__private_implementation__high_prec_dec__render_exponent_absent(\n dst, &h, precision, options);\n}\n" +
""
const BaseI64ConvSubmoduleC = "" +
@@ -103,8 +125,8 @@
"" +
"// --------\n\n// wuffs_base__render_number__first_hundred contains the decimal encodings of\n// the first one hundred numbers [0 ..= 99].\nstatic const uint8_t wuffs_base__render_number__first_hundred[200] = {\n '0', '0', '0', '1', '0', '2', '0', '3', '0', '4', //\n '0', '5', '0', '6', '0', '7', '0', '8', '0', '9', //\n '1', '0', '1', '1', '1', '2', '1', '3', '1', '4', //\n '1', '5', '1', '6', '1', '7', '1', '8', '1', '9', //\n '2', '0', '2', '1', '2', '2', '2', '3', '2', '4', //\n '2', '5', '2', '6', '2', '7', '2', '8', '2', '9', //\n '3', '0', '3', '1', '3', '2', '3', '3', '3', '4', //\n '3', '5', '3', '6', '3', '7', '3', '8', '3', '9', //\n '4', '0', '4', '1', '4', '2', '4', '3', '4', '4', //\n '4', '5', '4', '6', '4', '7', '4', '8', '4', '9', //\n '5', '0', '5', '1', '5', '2', '5', '3', '5', '4', //\n '5', '5', '5', '6', '5', '7', '5', '8', '5', '9', //\n '6', '0', '6', '1', '6', '2', '6', '3', '6', '4', //\n '6', '5', '6', '6', '6', '7', '6', '8', '6', '9', //\n '" +
"7', '0', '7', '1', '7', '2', '7', '3', '7', '4', //\n '7', '5', '7', '6', '7', '7', '7', '8', '7', '9', //\n '8', '0', '8', '1', '8', '2', '8', '3', '8', '4', //\n '8', '5', '8', '6', '8', '7', '8', '8', '8', '9', //\n '9', '0', '9', '1', '9', '2', '9', '3', '9', '4', //\n '9', '5', '9', '6', '9', '7', '9', '8', '9', '9', //\n};\n\nstatic size_t //\nwuffs_base__private_implementation__render_number_u64(wuffs_base__slice_u8 dst,\n uint64_t x,\n uint32_t options,\n bool neg) {\n uint8_t buf[WUFFS_BASE__U64__BYTE_LENGTH__MAX_INCL];\n uint8_t* ptr = &buf[0] + sizeof(buf);\n\n while (x >= 100) {\n size_t index = (x % 100) * 2;\n x /= 100;\n uint8_t s0 = wuffs_base__render_number__first_hundred[index + 0];\n uint8_t s1 = wuffs_base__render_number__first_hundred[index + 1];\n ptr -= 2;\n ptr[0] = s0;\n ptr[1] = s1;\n }\n\n if (x < 10) {\n " +
- " ptr -= 1;\n ptr[0] = (uint8_t)('0' + x);\n } else {\n size_t index = x * 2;\n uint8_t s0 = wuffs_base__render_number__first_hundred[index + 0];\n uint8_t s1 = wuffs_base__render_number__first_hundred[index + 1];\n ptr -= 2;\n ptr[0] = s0;\n ptr[1] = s1;\n }\n\n if (neg) {\n ptr -= 1;\n ptr[0] = '-';\n } else if (options & WUFFS_BASE__RENDER_NUMBER__LEADING_PLUS_SIGN) {\n ptr -= 1;\n ptr[0] = '+';\n }\n\n size_t n = sizeof(buf) - ((size_t)(ptr - &buf[0]));\n if (n > dst.len) {\n return 0;\n }\n memcpy(dst.ptr + ((options & WUFFS_BASE__RENDER_NUMBER__ALIGN_RIGHT)\n ? (dst.len - n)\n : 0),\n ptr, n);\n return n;\n}\n\nWUFFS_BASE__MAYBE_STATIC size_t //\nwuffs_base__render_number_i64(wuffs_base__slice_u8 dst,\n int64_t x,\n uint32_t options) {\n uint64_t u = (uint64_t)x;\n bool neg = x < 0;\n if (neg) {\n u = 1 + ~u;\n }\n return wuffs_base__private_implementation__render_number_u64(d" +
- "st, u, options,\n neg);\n}\n\nWUFFS_BASE__MAYBE_STATIC size_t //\nwuffs_base__render_number_u64(wuffs_base__slice_u8 dst,\n uint64_t x,\n uint32_t options) {\n return wuffs_base__private_implementation__render_number_u64(dst, x, options,\n false);\n}\n\n" +
+ " ptr -= 1;\n ptr[0] = (uint8_t)('0' + x);\n } else {\n size_t index = x * 2;\n uint8_t s0 = wuffs_base__render_number__first_hundred[index + 0];\n uint8_t s1 = wuffs_base__render_number__first_hundred[index + 1];\n ptr -= 2;\n ptr[0] = s0;\n ptr[1] = s1;\n }\n\n if (neg) {\n ptr -= 1;\n ptr[0] = '-';\n } else if (options & WUFFS_BASE__RENDER_NUMBER_XXX__LEADING_PLUS_SIGN) {\n ptr -= 1;\n ptr[0] = '+';\n }\n\n size_t n = sizeof(buf) - ((size_t)(ptr - &buf[0]));\n if (n > dst.len) {\n return 0;\n }\n memcpy(dst.ptr + ((options & WUFFS_BASE__RENDER_NUMBER_XXX__ALIGN_RIGHT)\n ? (dst.len - n)\n : 0),\n ptr, n);\n return n;\n}\n\nWUFFS_BASE__MAYBE_STATIC size_t //\nwuffs_base__render_number_i64(wuffs_base__slice_u8 dst,\n int64_t x,\n uint32_t options) {\n uint64_t u = (uint64_t)x;\n bool neg = x < 0;\n if (neg) {\n u = 1 + ~u;\n }\n return wuffs_base__private_implementation__render_numb" +
+ "er_u64(dst, u, options,\n neg);\n}\n\nWUFFS_BASE__MAYBE_STATIC size_t //\nwuffs_base__render_number_u64(wuffs_base__slice_u8 dst,\n uint64_t x,\n uint32_t options) {\n return wuffs_base__private_implementation__render_number_u64(dst, x, options,\n false);\n}\n\n" +
"" +
"// ---------------- Hexadecimal\n\nWUFFS_BASE__MAYBE_STATIC size_t //\nwuffs_base__hexadecimal__decode2(wuffs_base__slice_u8 dst,\n wuffs_base__slice_u8 src) {\n size_t src_len2 = src.len / 2;\n size_t len = dst.len < src_len2 ? dst.len : src_len2;\n uint8_t* d = dst.ptr;\n uint8_t* s = src.ptr;\n size_t n = len;\n\n while (n--) {\n *d = (uint8_t)((wuffs_base__parse_number__hexadecimal_digits[s[0]] << 4) |\n (wuffs_base__parse_number__hexadecimal_digits[s[1]] & 0x0F));\n d += 1;\n s += 2;\n }\n\n return len;\n}\n\nWUFFS_BASE__MAYBE_STATIC size_t //\nwuffs_base__hexadecimal__decode4(wuffs_base__slice_u8 dst,\n wuffs_base__slice_u8 src) {\n size_t src_len4 = src.len / 4;\n size_t len = dst.len < src_len4 ? dst.len : src_len4;\n uint8_t* d = dst.ptr;\n uint8_t* s = src.ptr;\n size_t n = len;\n\n while (n--) {\n *d = (uint8_t)((wuffs_base__parse_number__hexadecimal_digits[s[2]] << 4) |\n (wuffs_base__parse_number__hexa" +
"decimal_digits[s[3]] & 0x0F));\n d += 1;\n s += 4;\n }\n\n return len;\n}\n" +
@@ -231,8 +253,9 @@
"" +
"// --------\n\n// Flicks are a unit of time. One flick (frame-tick) is 1 / 705_600_000 of a\n// second. See https://github.com/OculusVR/Flicks\ntypedef int64_t wuffs_base__flicks;\n\n#define WUFFS_BASE__FLICKS_PER_SECOND ((uint64_t)705600000)\n#define WUFFS_BASE__FLICKS_PER_MILLISECOND ((uint64_t)705600)\n\n" +
"" +
- "// ---------------- Numeric Types\n\n// The helpers below are functions, instead of macros, because their arguments\n// can be an expression that we shouldn't evaluate more than once.\n//\n// They are static, so that linking multiple wuffs .o files won't complain about\n// duplicate function definitions.\n//\n// They are explicitly marked inline, even if modern compilers don't use the\n// inline attribute to guide optimizations such as inlining, to avoid the\n// -Wunused-function warning, and we like to compile with -Wall -Werror.\n\nstatic inline uint8_t //\nwuffs_base__u8__min(uint8_t x, uint8_t y) {\n return x < y ? x : y;\n}\n\nstatic inline uint8_t //\nwuffs_base__u8__max(uint8_t x, uint8_t y) {\n return x > y ? x : y;\n}\n\nstatic inline uint16_t //\nwuffs_base__u16__min(uint16_t x, uint16_t y) {\n return x < y ? x : y;\n}\n\nstatic inline uint16_t //\nwuffs_base__u16__max(uint16_t x, uint16_t y) {\n return x > y ? x : y;\n}\n\nstatic inline uint32_t //\nwuffs_base__u32__min(uint32_t x, uint32_t y) {\n return x < y ? x : y;\n}\n" +
- "\nstatic inline uint32_t //\nwuffs_base__u32__max(uint32_t x, uint32_t y) {\n return x > y ? x : y;\n}\n\nstatic inline uint64_t //\nwuffs_base__u64__min(uint64_t x, uint64_t y) {\n return x < y ? x : y;\n}\n\nstatic inline uint64_t //\nwuffs_base__u64__max(uint64_t x, uint64_t y) {\n return x > y ? x : y;\n}\n\n" +
+ "// ---------------- Numeric Types\n\n// The helpers below are functions, instead of macros, because their arguments\n// can be an expression that we shouldn't evaluate more than once.\n//\n// They are static, so that linking multiple wuffs .o files won't complain about\n// duplicate function definitions.\n//\n// They are explicitly marked inline, even if modern compilers don't use the\n// inline attribute to guide optimizations such as inlining, to avoid the\n// -Wunused-function warning, and we like to compile with -Wall -Werror.\n\nstatic inline int8_t //\nwuffs_base__i8__min(int8_t x, int8_t y) {\n return x < y ? x : y;\n}\n\nstatic inline int8_t //\nwuffs_base__i8__max(int8_t x, int8_t y) {\n return x > y ? x : y;\n}\n\nstatic inline int16_t //\nwuffs_base__i16__min(int16_t x, int16_t y) {\n return x < y ? x : y;\n}\n\nstatic inline int16_t //\nwuffs_base__i16__max(int16_t x, int16_t y) {\n return x > y ? x : y;\n}\n\nstatic inline int32_t //\nwuffs_base__i32__min(int32_t x, int32_t y) {\n return x < y ? x : y;\n}\n\nstatic inline " +
+ "int32_t //\nwuffs_base__i32__max(int32_t x, int32_t y) {\n return x > y ? x : y;\n}\n\nstatic inline int64_t //\nwuffs_base__i64__min(int64_t x, int64_t y) {\n return x < y ? x : y;\n}\n\nstatic inline int64_t //\nwuffs_base__i64__max(int64_t x, int64_t y) {\n return x > y ? x : y;\n}\n\nstatic inline uint8_t //\nwuffs_base__u8__min(uint8_t x, uint8_t y) {\n return x < y ? x : y;\n}\n\nstatic inline uint8_t //\nwuffs_base__u8__max(uint8_t x, uint8_t y) {\n return x > y ? x : y;\n}\n\nstatic inline uint16_t //\nwuffs_base__u16__min(uint16_t x, uint16_t y) {\n return x < y ? x : y;\n}\n\nstatic inline uint16_t //\nwuffs_base__u16__max(uint16_t x, uint16_t y) {\n return x > y ? x : y;\n}\n\nstatic inline uint32_t //\nwuffs_base__u32__min(uint32_t x, uint32_t y) {\n return x < y ? x : y;\n}\n\nstatic inline uint32_t //\nwuffs_base__u32__max(uint32_t x, uint32_t y) {\n return x > y ? x : y;\n}\n\nstatic inline uint64_t //\nwuffs_base__u64__min(uint64_t x, uint64_t y) {\n return x < y ? x : y;\n}\n\nstatic inline uint64_t //\nwuffs_base__u64__m" +
+ "ax(uint64_t x, uint64_t y) {\n return x > y ? x : y;\n}\n\n" +
"" +
"// --------\n\n// Saturating arithmetic (sat_add, sat_sub) branchless bit-twiddling algorithms\n// are per https://locklessinc.com/articles/sat_arithmetic/\n//\n// It is important that the underlying types are unsigned integers, as signed\n// integer arithmetic overflow is undefined behavior in C.\n\nstatic inline uint8_t //\nwuffs_base__u8__sat_add(uint8_t x, uint8_t y) {\n uint8_t res = (uint8_t)(x + y);\n res |= (uint8_t)(-(res < x));\n return res;\n}\n\nstatic inline uint8_t //\nwuffs_base__u8__sat_sub(uint8_t x, uint8_t y) {\n uint8_t res = (uint8_t)(x - y);\n res &= (uint8_t)(-(res <= x));\n return res;\n}\n\nstatic inline uint16_t //\nwuffs_base__u16__sat_add(uint16_t x, uint16_t y) {\n uint16_t res = (uint16_t)(x + y);\n res |= (uint16_t)(-(res < x));\n return res;\n}\n\nstatic inline uint16_t //\nwuffs_base__u16__sat_sub(uint16_t x, uint16_t y) {\n uint16_t res = (uint16_t)(x - y);\n res &= (uint16_t)(-(res <= x));\n return res;\n}\n\nstatic inline uint32_t //\nwuffs_base__u32__sat_add(uint32_t x, uint32_t y) {\n uint32" +
"_t res = (uint32_t)(x + y);\n res |= (uint32_t)(-(res < x));\n return res;\n}\n\nstatic inline uint32_t //\nwuffs_base__u32__sat_sub(uint32_t x, uint32_t y) {\n uint32_t res = (uint32_t)(x - y);\n res &= (uint32_t)(-(res <= x));\n return res;\n}\n\nstatic inline uint64_t //\nwuffs_base__u64__sat_add(uint64_t x, uint64_t y) {\n uint64_t res = (uint64_t)(x + y);\n res |= (uint64_t)(-(res < x));\n return res;\n}\n\nstatic inline uint64_t //\nwuffs_base__u64__sat_sub(uint64_t x, uint64_t y) {\n uint64_t res = (uint64_t)(x - y);\n res &= (uint64_t)(-(res <= x));\n return res;\n}\n\n" +
@@ -417,7 +440,9 @@
""
const BaseStrConvPublicH = "" +
- "// ---------------- String Conversions\n\n// Options (bitwise or'ed together) for wuffs_base__render_number_etc\n// functions.\n\n#define WUFFS_BASE__RENDER_NUMBER__DEFAULT_OPTIONS ((uint32_t)0x00000000)\n\n// WUFFS_BASE__RENDER_NUMBER__ALIGN_RIGHT means to render to the right side\n// (higher indexes) of the destination slice, leaving any untouched bytes on\n// the left side (lower indexes). The default is vice versa: rendering on the\n// left with slack on the right.\n#define WUFFS_BASE__RENDER_NUMBER__ALIGN_RIGHT ((uint32_t)0x00000001)\n\n// WUFFS_BASE__RENDER_NUMBER__LEADING_PLUS_SIGN means to render the unnecessary\n// leading \"+\" for non-negative numbers: \"+0\" and \"+123\", not \"0\" and \"123\".\n#define WUFFS_BASE__RENDER_NUMBER__LEADING_PLUS_SIGN ((uint32_t)0x00000002)\n\n" +
+ "// ---------------- String Conversions\n\n// Options (bitwise or'ed together) for wuffs_base__render_number_xxx\n// functions. The XXX options apply to both integer and floating point. The FXX\n// options apply only to floating point.\n\n#define WUFFS_BASE__RENDER_NUMBER_XXX__DEFAULT_OPTIONS ((uint32_t)0x00000000)\n\n// WUFFS_BASE__RENDER_NUMBER_XXX__ALIGN_RIGHT means to render to the right side\n// (higher indexes) of the destination slice, leaving any untouched bytes on\n// the left side (lower indexes). The default is vice versa: rendering on the\n// left with slack on the right.\n#define WUFFS_BASE__RENDER_NUMBER_XXX__ALIGN_RIGHT ((uint32_t)0x00000001)\n\n// WUFFS_BASE__RENDER_NUMBER_XXX__LEADING_PLUS_SIGN means to render the leading\n// \"+\" for non-negative numbers: \"+0\" and \"+12.3\" instead of \"0\" and \"12.3\".\n#define WUFFS_BASE__RENDER_NUMBER_XXX__LEADING_PLUS_SIGN ((uint32_t)0x00000002)\n\n// WUFFS_BASE__RENDER_NUMBER_FXX__DECIMAL_SEPARATOR_IS_A_COMMA means to render\n// one-and-a-half as \"1,5\" instead of \"1.5\".\n#define " +
+ "WUFFS_BASE__RENDER_NUMBER_FXX__DECIMAL_SEPARATOR_IS_A_COMMA \\\n ((uint32_t)0x00000100)\n\n// WUFFS_BASE__RENDER_NUMBER_FXX__EXPONENT_ETC means whether to never\n// (EXPONENT_ABSENT, equivalent to printf's \"%f\") or to always\n// (EXPONENT_PRESENT, equivalent to printf's \"%e\") render a floating point\n// number as \"1.23e+05\" instead of \"123000\".\n//\n// Having both bits set is the same has having neither bit set, where the\n// notation used depends on whether the exponent is sufficiently large: \"0.5\"\n// is preferred over \"5e-01\" but \"5e-09\" is preferred over \"0.000000005\".\n#define WUFFS_BASE__RENDER_NUMBER_FXX__EXPONENT_ABSENT ((uint32_t)0x00000200)\n#define WUFFS_BASE__RENDER_NUMBER_FXX__EXPONENT_PRESENT ((uint32_t)0x00000400)\n\n// WUFFS_BASE__RENDER_NUMBER_FXX__JUST_ENOUGH_PRECISION means to render the\n// smallest number of digits so that parsing the resultant string will recover\n// the same double-precision floating point number.\n//\n// For example, double-precision cannot distinguish between 0.3 and\n// 0.2999999999999" +
+ "99988897769753748434595763683319091796875, so when this bit\n// is set, rendering the latter will produce \"0.3\" but rendering\n// 0.3000000000000000444089209850062616169452667236328125 will produce\n// \"0.30000000000000004\".\n#define WUFFS_BASE__RENDER_NUMBER_FXX__JUST_ENOUGH_PRECISION \\\n ((uint32_t)0x00000800)\n\n" +
"" +
"// ---------------- IEEE 754 Floating Point\n\n// wuffs_base__parse_number_f64 parses the floating point number in s. For\n// example, if s contains the bytes \"1.5\" then it will return the double 1.5.\n//\n// It returns an error if s does not contain a floating point number.\n//\n// It does not necessarily return an error if the conversion is lossy, e.g. if\n// s is \"0.3\", which double-precision floating point cannot represent exactly.\n//\n// Similarly, the returned value may be infinite (and no error returned) even\n// if s was not \"inf\", when the input is nominally finite but sufficiently\n// larger than DBL_MAX, about 1.8e+308.\n//\n// It is similar to the C standard library's strtod function, but:\n// - Errors are returned in-band (in a result type), not out-of-band (errno).\n// - It takes a slice (a pointer and length), not a NUL-terminated C string.\n// - It does not take an optional endptr argument. It does not allow a partial\n// parse: it returns an error unless all of s is consumed.\n// - It does not allow whi" +
"tespace, leading or otherwise.\n// - It does not allow unnecessary leading zeroes (\"0\" is valid and its sole\n// zero is necessary). All of \"00\", \"0644\" and \"00.7\" are invalid.\n// - It is not affected by i18n / l10n settings such as environment variables.\n// - Conversely, it always accepts either ',' or '.' as a decimal separator.\n// In particular, \"3,141,592\" is always invalid but \"3,141\" is always valid\n// (and approximately π). The caller is responsible for e.g. previously\n// rejecting or filtering s if it contains a comma, if that is unacceptable\n// to the caller. For example, JSON numbers always use a dot '.' and never a\n// comma ',', regardless of the LOCALE environment variable.\n// - It does allow arbitrary underscores. For example, \"_3.141_592\" would\n// successfully parse, again approximately π.\n// - It does allow \"inf\", \"+Infinity\" and \"-NAN\", case insensitive, but it\n// does not permit \"nan\" to be followed by an integer mantissa.\n// - It does not allow hexadecimal float" +
@@ -429,8 +454,9 @@
"ted C string.\n// - It does not take an optional endptr argument. It does not allow a partial\n// parse: it returns an error unless all of s is consumed.\n// - It does not allow whitespace, leading or otherwise.\n// - It does not allow a leading '+' or '-'.\n// - It does not allow unnecessary leading zeroes (\"0\" is valid and its sole\n// zero is necessary). All of \"00\", \"0644\" and \"007\" are invalid.\n// - It does not take a base argument (e.g. base 10 vs base 16). Instead, it\n// always accepts both decimal (e.g \"1234\", \"0d5678\") and hexadecimal (e.g.\n// \"0x9aBC\"). The caller is responsible for prior filtering of e.g. hex\n// numbers if they are unwanted. For example, Wuffs' JSON decoder will only\n// produce a wuffs_base__token for decimal numbers, not hexadecimal.\n// - It is not affected by i18n / l10n settings such as environment variables.\n// - It does allow arbitrary underscores, except inside the optional 2-byte\n// opening \"0d\" or \"0X\" that denotes base-10 or base-16. For example,\n// " +
" \"__0D_1_002\" would successfully parse as \"one thousand and two\".\nWUFFS_BASE__MAYBE_STATIC wuffs_base__result_u64 //\nwuffs_base__parse_number_u64(wuffs_base__slice_u8 s);\n\n" +
"" +
- "// --------\n\n#define WUFFS_BASE__I64__BYTE_LENGTH__MAX_INCL 20\n#define WUFFS_BASE__U64__BYTE_LENGTH__MAX_INCL 21\n\n// wuffs_base__render_number_i64 writes the decimal encoding of x to dst and\n// returns the number of bytes written. If dst is shorter than the entire\n// encoding, it returns 0 (and no bytes are written).\n//\n// dst will never be too short if its length is at least 20, also known as\n// WUFFS_BASE__I64__BYTE_LENGTH__MAX_INCL.\nWUFFS_BASE__MAYBE_STATIC size_t //\nwuffs_base__render_number_i64(wuffs_base__slice_u8 dst,\n int64_t x,\n uint32_t options);\n\n// wuffs_base__render_number_u64 writes the decimal encoding of x to dst and\n// returns the number of bytes written. If dst is shorter than the entire\n// encoding, it returns 0 (and no bytes are written).\n//\n// dst will never be too short if its length is at least 21, also known as\n// WUFFS_BASE__U64__BYTE_LENGTH__MAX_INCL.\nWUFFS_BASE__MAYBE_STATIC size_t //\nwuffs_base__render_number_u64(wuffs_bas" +
- "e__slice_u8 dst,\n uint64_t x,\n uint32_t options);\n\n" +
+ "// --------\n\n#define WUFFS_BASE__I64__BYTE_LENGTH__MAX_INCL 20\n#define WUFFS_BASE__U64__BYTE_LENGTH__MAX_INCL 21\n\n// wuffs_base__render_number_f64 writes the decimal encoding of x to dst and\n// returns the number of bytes written. If dst is shorter than the entire\n// encoding, it returns 0 (and no bytes are written).\n//\n// For those familiar with C's printf or Go's fmt.Printf functions:\n// - \"%e\" means the WUFFS_BASE__RENDER_NUMBER_FXX__EXPONENT_PRESENT option.\n// - \"%f\" means the WUFFS_BASE__RENDER_NUMBER_FXX__EXPONENT_ABSENT option.\n// - \"%g\" means neither or both bits are set.\n//\n// The precision argument controls the number of digits rendered, excluding the\n// exponent (the \"e+05\" in \"1.23e+05\"):\n// - for \"%e\" and \"%f\" it is the number of digits after the decimal separator,\n// - for \"%g\" it is the number of significant digits (and trailing zeroes are\n// removed).\n//\n// A precision of 6 gives similar output to printf's defaults.\n//\n// A precision greater than 4095 is equivalent to 4095.\n//\n// The " +
+ "precision argument is ignored when the\n// WUFFS_BASE__RENDER_NUMBER_FXX__JUST_ENOUGH_PRECISION option is set. This is\n// similar to Go's strconv.FormatFloat with a negative (i.e. non-sensical)\n// precision, but there is no corresponding feature in C's printf.\n//\n// Extreme values of x will be rendered as \"NaN\", \"Inf\" (or \"+Inf\" if the\n// WUFFS_BASE__RENDER_NUMBER_XXX__LEADING_PLUS_SIGN option is set) or \"-Inf\".\nWUFFS_BASE__MAYBE_STATIC size_t //\nwuffs_base__render_number_f64(wuffs_base__slice_u8 dst,\n double x,\n uint32_t precision,\n uint32_t options);\n\n// wuffs_base__render_number_i64 writes the decimal encoding of x to dst and\n// returns the number of bytes written. If dst is shorter than the entire\n// encoding, it returns 0 (and no bytes are written).\n//\n// dst will never be too short if its length is at least 20, also known as\n// WUFFS_BASE__I64__BYTE_LENGTH__MAX_INCL.\nWUFFS_BASE__MAYBE_STATIC size_t //\nwuffs_base__ren" +
+ "der_number_i64(wuffs_base__slice_u8 dst,\n int64_t x,\n uint32_t options);\n\n// wuffs_base__render_number_u64 writes the decimal encoding of x to dst and\n// returns the number of bytes written. If dst is shorter than the entire\n// encoding, it returns 0 (and no bytes are written).\n//\n// dst will never be too short if its length is at least 21, also known as\n// WUFFS_BASE__U64__BYTE_LENGTH__MAX_INCL.\nWUFFS_BASE__MAYBE_STATIC size_t //\nwuffs_base__render_number_u64(wuffs_base__slice_u8 dst,\n uint64_t x,\n uint32_t options);\n\n" +
"" +
"// ---------------- Hexadecimal\n\n// wuffs_base__hexadecimal__decode2 converts \"6A6b\" to \"jk\", where e.g. 'j' is\n// U+006A. There are 2 source bytes for every destination byte.\n//\n// It returns the number of dst bytes written: the minimum of dst.len and\n// (src.len / 2). Excess source bytes are ignored.\n//\n// It assumes that the src bytes are two hexadecimal digits (0-9, A-F, a-f),\n// repeated. It may write nonsense bytes if not, although it will not read or\n// write out of bounds.\nWUFFS_BASE__MAYBE_STATIC size_t //\nwuffs_base__hexadecimal__decode2(wuffs_base__slice_u8 dst,\n wuffs_base__slice_u8 src);\n\n// wuffs_base__hexadecimal__decode4 converts \"\\\\x6A\\\\x6b\" to \"jk\", where e.g.\n// 'j' is U+006A. There are 4 source bytes for every destination byte.\n//\n// It returns the number of dst bytes written: the minimum of dst.len and\n// (src.len / 4). Excess source bytes are ignored.\n//\n// It assumes that the src bytes are two ignored bytes and then two hexadecimal\n// digits (0-9, A-F, a" +
"-f), repeated. It may write nonsense bytes if not,\n// although it will not read or write out of bounds.\nWUFFS_BASE__MAYBE_STATIC size_t //\nwuffs_base__hexadecimal__decode4(wuffs_base__slice_u8 dst,\n wuffs_base__slice_u8 src);\n\n" +
diff --git a/release/c/wuffs-unsupported-snapshot.c b/release/c/wuffs-unsupported-snapshot.c
index c4db729..e0161ee 100644
--- a/release/c/wuffs-unsupported-snapshot.c
+++ b/release/c/wuffs-unsupported-snapshot.c
@@ -354,6 +354,46 @@
// inline attribute to guide optimizations such as inlining, to avoid the
// -Wunused-function warning, and we like to compile with -Wall -Werror.
+static inline int8_t //
+wuffs_base__i8__min(int8_t x, int8_t y) {
+ return x < y ? x : y;
+}
+
+static inline int8_t //
+wuffs_base__i8__max(int8_t x, int8_t y) {
+ return x > y ? x : y;
+}
+
+static inline int16_t //
+wuffs_base__i16__min(int16_t x, int16_t y) {
+ return x < y ? x : y;
+}
+
+static inline int16_t //
+wuffs_base__i16__max(int16_t x, int16_t y) {
+ return x > y ? x : y;
+}
+
+static inline int32_t //
+wuffs_base__i32__min(int32_t x, int32_t y) {
+ return x < y ? x : y;
+}
+
+static inline int32_t //
+wuffs_base__i32__max(int32_t x, int32_t y) {
+ return x > y ? x : y;
+}
+
+static inline int64_t //
+wuffs_base__i64__min(int64_t x, int64_t y) {
+ return x < y ? x : y;
+}
+
+static inline int64_t //
+wuffs_base__i64__max(int64_t x, int64_t y) {
+ return x > y ? x : y;
+}
+
static inline uint8_t //
wuffs_base__u8__min(uint8_t x, uint8_t y) {
return x < y ? x : y;
@@ -3866,20 +3906,49 @@
// ---------------- String Conversions
-// Options (bitwise or'ed together) for wuffs_base__render_number_etc
-// functions.
+// Options (bitwise or'ed together) for wuffs_base__render_number_xxx
+// functions. The XXX options apply to both integer and floating point. The FXX
+// options apply only to floating point.
-#define WUFFS_BASE__RENDER_NUMBER__DEFAULT_OPTIONS ((uint32_t)0x00000000)
+#define WUFFS_BASE__RENDER_NUMBER_XXX__DEFAULT_OPTIONS ((uint32_t)0x00000000)
-// WUFFS_BASE__RENDER_NUMBER__ALIGN_RIGHT means to render to the right side
+// WUFFS_BASE__RENDER_NUMBER_XXX__ALIGN_RIGHT means to render to the right side
// (higher indexes) of the destination slice, leaving any untouched bytes on
// the left side (lower indexes). The default is vice versa: rendering on the
// left with slack on the right.
-#define WUFFS_BASE__RENDER_NUMBER__ALIGN_RIGHT ((uint32_t)0x00000001)
+#define WUFFS_BASE__RENDER_NUMBER_XXX__ALIGN_RIGHT ((uint32_t)0x00000001)
-// WUFFS_BASE__RENDER_NUMBER__LEADING_PLUS_SIGN means to render the unnecessary
-// leading "+" for non-negative numbers: "+0" and "+123", not "0" and "123".
-#define WUFFS_BASE__RENDER_NUMBER__LEADING_PLUS_SIGN ((uint32_t)0x00000002)
+// WUFFS_BASE__RENDER_NUMBER_XXX__LEADING_PLUS_SIGN means to render the leading
+// "+" for non-negative numbers: "+0" and "+12.3" instead of "0" and "12.3".
+#define WUFFS_BASE__RENDER_NUMBER_XXX__LEADING_PLUS_SIGN ((uint32_t)0x00000002)
+
+// WUFFS_BASE__RENDER_NUMBER_FXX__DECIMAL_SEPARATOR_IS_A_COMMA means to render
+// one-and-a-half as "1,5" instead of "1.5".
+#define WUFFS_BASE__RENDER_NUMBER_FXX__DECIMAL_SEPARATOR_IS_A_COMMA \
+ ((uint32_t)0x00000100)
+
+// WUFFS_BASE__RENDER_NUMBER_FXX__EXPONENT_ETC means whether to never
+// (EXPONENT_ABSENT, equivalent to printf's "%f") or to always
+// (EXPONENT_PRESENT, equivalent to printf's "%e") render a floating point
+// number as "1.23e+05" instead of "123000".
+//
+// Having both bits set is the same has having neither bit set, where the
+// notation used depends on whether the exponent is sufficiently large: "0.5"
+// is preferred over "5e-01" but "5e-09" is preferred over "0.000000005".
+#define WUFFS_BASE__RENDER_NUMBER_FXX__EXPONENT_ABSENT ((uint32_t)0x00000200)
+#define WUFFS_BASE__RENDER_NUMBER_FXX__EXPONENT_PRESENT ((uint32_t)0x00000400)
+
+// WUFFS_BASE__RENDER_NUMBER_FXX__JUST_ENOUGH_PRECISION means to render the
+// smallest number of digits so that parsing the resultant string will recover
+// the same double-precision floating point number.
+//
+// For example, double-precision cannot distinguish between 0.3 and
+// 0.299999999999999988897769753748434595763683319091796875, so when this bit
+// is set, rendering the latter will produce "0.3" but rendering
+// 0.3000000000000000444089209850062616169452667236328125 will produce
+// "0.30000000000000004".
+#define WUFFS_BASE__RENDER_NUMBER_FXX__JUST_ENOUGH_PRECISION \
+ ((uint32_t)0x00000800)
// ---------------- IEEE 754 Floating Point
@@ -3998,6 +4067,38 @@
#define WUFFS_BASE__I64__BYTE_LENGTH__MAX_INCL 20
#define WUFFS_BASE__U64__BYTE_LENGTH__MAX_INCL 21
+// wuffs_base__render_number_f64 writes the decimal encoding of x to dst and
+// returns the number of bytes written. If dst is shorter than the entire
+// encoding, it returns 0 (and no bytes are written).
+//
+// For those familiar with C's printf or Go's fmt.Printf functions:
+// - "%e" means the WUFFS_BASE__RENDER_NUMBER_FXX__EXPONENT_PRESENT option.
+// - "%f" means the WUFFS_BASE__RENDER_NUMBER_FXX__EXPONENT_ABSENT option.
+// - "%g" means neither or both bits are set.
+//
+// The precision argument controls the number of digits rendered, excluding the
+// exponent (the "e+05" in "1.23e+05"):
+// - for "%e" and "%f" it is the number of digits after the decimal separator,
+// - for "%g" it is the number of significant digits (and trailing zeroes are
+// removed).
+//
+// A precision of 6 gives similar output to printf's defaults.
+//
+// A precision greater than 4095 is equivalent to 4095.
+//
+// The precision argument is ignored when the
+// WUFFS_BASE__RENDER_NUMBER_FXX__JUST_ENOUGH_PRECISION option is set. This is
+// similar to Go's strconv.FormatFloat with a negative (i.e. non-sensical)
+// precision, but there is no corresponding feature in C's printf.
+//
+// Extreme values of x will be rendered as "NaN", "Inf" (or "+Inf" if the
+// WUFFS_BASE__RENDER_NUMBER_XXX__LEADING_PLUS_SIGN option is set) or "-Inf".
+WUFFS_BASE__MAYBE_STATIC size_t //
+wuffs_base__render_number_f64(wuffs_base__slice_u8 dst,
+ double x,
+ uint32_t precision,
+ uint32_t options);
+
// wuffs_base__render_number_i64 writes the decimal encoding of x to dst and
// returns the number of bytes written. If dst is shorter than the entire
// encoding, it returns 0 (and no bytes are written).
@@ -8840,8 +8941,8 @@
// ---------------- IEEE 754 Floating Point
-#define WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DECIMAL_POINT__RANGE 1023
-#define WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DIGITS_PRECISION 500
+#define WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DECIMAL_POINT__RANGE 2047
+#define WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DIGITS_PRECISION 800
// WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__SHIFT__MAX_INCL is the largest N
// such that ((10 << N) < (1 << 64)).
@@ -8851,14 +8952,14 @@
// fixed precision floating point decimal number, augmented with ±infinity
// values, but it cannot represent NaN (Not a Number).
//
-// "High precision" means that the mantissa holds 500 decimal digits. 500 is
+// "High precision" means that the mantissa holds 800 decimal digits. 800 is
// WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DIGITS_PRECISION.
//
// An HPD isn't for general purpose arithmetic, only for conversions to and
// from IEEE 754 double-precision floating point, where the largest and
// smallest positive, finite values are approximately 1.8e+308 and 4.9e-324.
-// HPD exponents above +1023 mean infinity, below -1023 mean zero. The ±1023
-// bounds are further away from zero than ±(324 + 500), where 500 and 1023 is
+// HPD exponents above +2047 mean infinity, below -2047 mean zero. The ±2047
+// bounds are further away from zero than ±(324 + 800), where 800 and 2047 is
// WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DIGITS_PRECISION and
// WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DECIMAL_POINT__RANGE.
//
@@ -8880,8 +8981,8 @@
// - A decimal_point of +4 means "7890."
// - A decimal_point of +5 means "78900."
//
-// As above, a decimal_point higher than +1023 means that the overall value is
-// infinity, lower than -1023 means zero.
+// As above, a decimal_point higher than +2047 means that the overall value is
+// infinity, lower than -2047 means zero.
//
// negative is a sign bit. An HPD can distinguish positive and negative zero.
//
@@ -8913,6 +9014,48 @@
}
}
+// wuffs_base__private_implementation__high_prec_dec__assign sets h to
+// represent the number x.
+//
+// Preconditions:
+// - h is non-NULL.
+static void //
+wuffs_base__private_implementation__high_prec_dec__assign(
+ wuffs_base__private_implementation__high_prec_dec* h,
+ uint64_t x,
+ bool negative) {
+ uint32_t n = 0;
+
+ // Set h->digits.
+ if (x > 0) {
+ // Calculate the digits, working right-to-left. After we determine n (how
+ // many digits there are), copy from buf to h->digits.
+ //
+ // UINT64_MAX, 18446744073709551615, is 20 digits long. It can be faster to
+ // copy a constant number of bytes than a variable number (20 instead of
+ // n). Make buf large enough (and start writing to it from the middle) so
+ // that can we always copy 20 bytes: the slice buf[(20-n) .. (40-n)].
+ uint8_t buf[40] = {0};
+ uint8_t* ptr = &buf[20];
+ do {
+ uint64_t remaining = x / 10;
+ x -= remaining * 10;
+ ptr--;
+ *ptr = (uint8_t)x;
+ n++;
+ x = remaining;
+ } while (x > 0);
+ memcpy(h->digits, ptr, 20);
+ }
+
+ // Set h's other fields.
+ h->num_digits = n;
+ h->decimal_point = (int32_t)n;
+ h->negative = negative;
+ h->truncated = false;
+ wuffs_base__private_implementation__high_prec_dec__trim(h);
+}
+
static wuffs_base__status //
wuffs_base__private_implementation__high_prec_dec__parse(
wuffs_base__private_implementation__high_prec_dec* h,
@@ -9288,6 +9431,11 @@
// wuffs_base__private_implementation__high_prec_dec__rounded_integer and
// wuffs_base__private_implementation__high_prec_dec__lshift_num_new_digits
// have the same preconditions.
+//
+// wuffs_base__private_implementation__high_prec_dec__lshift keeps the first
+// two preconditions but not the last two. Its shift argument is signed and
+// does not need to be "small": zero is a no-op, positive means left shift and
+// negative means right shift.
static void //
wuffs_base__private_implementation__high_prec_dec__small_lshift(
@@ -9401,6 +9549,254 @@
wuffs_base__private_implementation__high_prec_dec__trim(h);
}
+static void //
+wuffs_base__private_implementation__high_prec_dec__lshift(
+ wuffs_base__private_implementation__high_prec_dec* h,
+ int32_t shift) {
+ if (shift > 0) {
+ while (shift > +WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__SHIFT__MAX_INCL) {
+ wuffs_base__private_implementation__high_prec_dec__small_lshift(
+ h, WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__SHIFT__MAX_INCL);
+ shift -= WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__SHIFT__MAX_INCL;
+ }
+ wuffs_base__private_implementation__high_prec_dec__small_lshift(
+ h, ((uint32_t)(+shift)));
+ } else if (shift < 0) {
+ while (shift < -WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__SHIFT__MAX_INCL) {
+ wuffs_base__private_implementation__high_prec_dec__small_rshift(
+ h, WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__SHIFT__MAX_INCL);
+ shift += WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__SHIFT__MAX_INCL;
+ }
+ wuffs_base__private_implementation__high_prec_dec__small_rshift(
+ h, ((uint32_t)(-shift)));
+ }
+}
+
+// --------
+
+// wuffs_base__private_implementation__high_prec_dec__round_etc rounds h's
+// number. For those functions that take an n argument, rounding produces at
+// most n digits (which is not necessarily at most n decimal places). Negative
+// n values are ignored, as well as any n greater than or equal to h's number
+// of digits. The etc__round_just_enough function implicitly chooses an n to
+// implement WUFFS_BASE__RENDER_NUMBER_FXX__JUST_ENOUGH_PRECISION.
+//
+// Preconditions:
+// - h is non-NULL.
+// - h->decimal_point is "not extreme".
+//
+// "Not extreme" means within
+// ±WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DECIMAL_POINT__RANGE.
+
+static void //
+wuffs_base__private_implementation__high_prec_dec__round_down(
+ wuffs_base__private_implementation__high_prec_dec* h,
+ int32_t n) {
+ if ((n < 0) || (h->num_digits <= (uint32_t)n)) {
+ return;
+ }
+ h->num_digits = (uint32_t)(n);
+ wuffs_base__private_implementation__high_prec_dec__trim(h);
+}
+
+static void //
+wuffs_base__private_implementation__high_prec_dec__round_up(
+ wuffs_base__private_implementation__high_prec_dec* h,
+ int32_t n) {
+ if ((n < 0) || (h->num_digits <= (uint32_t)n)) {
+ return;
+ }
+
+ for (n--; n >= 0; n--) {
+ if (h->digits[n] < 9) {
+ h->digits[n]++;
+ h->num_digits = (uint32_t)(n + 1);
+ return;
+ }
+ }
+
+ // The number is all 9s. Change to a single 1 and adjust the decimal point.
+ h->digits[0] = 1;
+ h->num_digits = 1;
+ h->decimal_point++;
+}
+
+static void //
+wuffs_base__private_implementation__high_prec_dec__round_nearest(
+ wuffs_base__private_implementation__high_prec_dec* h,
+ int32_t n) {
+ if ((n < 0) || (h->num_digits <= (uint32_t)n)) {
+ return;
+ }
+ bool up = h->digits[n] >= 5;
+ if ((h->digits[n] == 5) && ((n + 1) == ((int32_t)(h->num_digits)))) {
+ up = h->truncated || //
+ ((n > 0) && ((h->digits[n - 1] & 1) != 0));
+ }
+
+ if (up) {
+ wuffs_base__private_implementation__high_prec_dec__round_up(h, n);
+ } else {
+ wuffs_base__private_implementation__high_prec_dec__round_down(h, n);
+ }
+}
+
+static void //
+wuffs_base__private_implementation__high_prec_dec__round_just_enough(
+ wuffs_base__private_implementation__high_prec_dec* h,
+ int32_t exp2,
+ uint64_t mantissa) {
+ // The magic numbers 52 and 53 in this function are because IEEE 754 double
+ // precision has 52 mantissa bits.
+ //
+ // Let f be the floating point number represented by exp2 and mantissa (and
+ // also the number in h): the number (mantissa * (2 ** (exp2 - 52))).
+ //
+ // If f is zero, we can return early.
+ if (mantissa == 0) {
+ return;
+ }
+
+ // The smallest normal f has an exp2 of -1022 and a mantissa of (1 << 52).
+ // Subnormal numbers have the same exp2 but a smaller mantissa.
+ static const int32_t min_incl_normal_exp2 = -1022;
+ static const uint64_t min_incl_normal_mantissa = 0x0010000000000000ul;
+
+ // Compute lower and upper bounds such that any number between them (possibly
+ // inclusive) will round to f. First, the lower bound. Our number f is:
+ // ((mantissa + 0) * (2 ** ( exp2 - 52)))
+ //
+ // The next lowest floating point number is:
+ // ((mantissa - 1) * (2 ** ( exp2 - 52)))
+ // unless (mantissa - 1) drops the (1 << 52) bit and exp2 is not the
+ // min_incl_normal_exp2. Either way, call it:
+ // ((l_mantissa) * (2 ** (l_exp2 - 52)))
+ //
+ // The lower bound is halfway between them (noting that 52 became 53):
+ // (((2 * l_mantissa) + 1) * (2 ** (l_exp2 - 53)))
+ int32_t l_exp2 = exp2;
+ uint64_t l_mantissa = mantissa - 1;
+ if ((exp2 > min_incl_normal_exp2) && (mantissa <= min_incl_normal_mantissa)) {
+ l_exp2 = exp2 - 1;
+ l_mantissa = (2 * mantissa) - 1;
+ }
+ wuffs_base__private_implementation__high_prec_dec lower;
+ wuffs_base__private_implementation__high_prec_dec__assign(
+ &lower, (2 * l_mantissa) + 1, false);
+ wuffs_base__private_implementation__high_prec_dec__lshift(&lower,
+ l_exp2 - 53);
+
+ // Next, the upper bound. Our number f is:
+ // ((mantissa + 0) * (2 ** (exp2 - 52)))
+ //
+ // The next highest floating point number is:
+ // ((mantissa + 1) * (2 ** (exp2 - 52)))
+ //
+ // The upper bound is halfway between them (noting that 52 became 53):
+ // (((2 * mantissa) + 1) * (2 ** (exp2 - 53)))
+ wuffs_base__private_implementation__high_prec_dec upper;
+ wuffs_base__private_implementation__high_prec_dec__assign(
+ &upper, (2 * mantissa) + 1, false);
+ wuffs_base__private_implementation__high_prec_dec__lshift(&upper, exp2 - 53);
+
+ // The lower and upper bounds are possible outputs only if the original
+ // mantissa is even, so that IEEE round-to-even would round to the original
+ // mantissa and not its neighbors.
+ bool inclusive = (mantissa & 1) == 0;
+
+ // As we walk the digits, we want to know whether rounding up would fall
+ // within the upper bound. This is tracked by upper_delta:
+ // - When -1, the digits of h and upper are the same so far.
+ // - When +0, we saw a difference of 1 between h and upper on a previous
+ // digit and subsequently only 9s for h and 0s for upper. Thus, rounding
+ // up may fall outside of the bound if !inclusive.
+ // - When +1, the difference is greater than 1 and we know that rounding up
+ // falls within the bound.
+ //
+ // This is a state machine with three states. The numerical value for each
+ // state (-1, +0 or +1) isn't important, other than their order.
+ int upper_delta = -1;
+
+ // We can now figure out the shortest number of digits required. Walk the
+ // digits until h has distinguished itself from lower or upper.
+ //
+ // The zi and zd variables are indexes and digits, for z in l (lower), h (the
+ // number) and u (upper).
+ //
+ // The lower, h and upper numbers may have their decimal points at different
+ // places. In this case, upper is the longest, so we iterate ui starting from
+ // 0 and iterate li and hi starting from either 0 or -1.
+ int32_t ui = 0;
+ for (;; ui++) {
+ // Calculate hd, the middle number's digit.
+ int32_t hi = ui - upper.decimal_point + h->decimal_point;
+ if (hi >= ((int32_t)(h->num_digits))) {
+ break;
+ }
+ uint8_t hd = (((uint32_t)hi) < h->num_digits) ? h->digits[hi] : 0;
+
+ // Calculate ld, the lower bound's digit.
+ int32_t li = ui - upper.decimal_point + lower.decimal_point;
+ uint8_t ld = (((uint32_t)li) < lower.num_digits) ? lower.digits[li] : 0;
+
+ // We can round down (truncate) if lower has a different digit than h or if
+ // lower is inclusive and is exactly the result of rounding down (i.e. we
+ // have reached the final digit of lower).
+ bool can_round_down =
+ (ld != hd) || //
+ (inclusive && ((li + 1) == ((int32_t)(lower.num_digits))));
+
+ // Calculate ud, the upper bound's digit, and update upper_delta.
+ uint8_t ud = (((uint32_t)ui) < upper.num_digits) ? upper.digits[ui] : 0;
+ if (upper_delta < 0) {
+ if ((hd + 1) < ud) {
+ // For example:
+ // h = 12345???
+ // upper = 12347???
+ upper_delta = +1;
+ } else if (hd != ud) {
+ // For example:
+ // h = 12345???
+ // upper = 12346???
+ upper_delta = +0;
+ }
+ } else if (upper_delta == 0) {
+ if ((hd != 9) || (ud != 0)) {
+ // For example:
+ // h = 1234598?
+ // upper = 1234600?
+ upper_delta = +1;
+ }
+ }
+
+ // We can round up if upper has a different digit than h and either upper
+ // is inclusive or upper is bigger than the result of rounding up.
+ bool can_round_up =
+ (upper_delta > 0) || //
+ ((upper_delta == 0) && //
+ (inclusive || ((ui + 1) < ((int32_t)(upper.num_digits)))));
+
+ // If we can round either way, round to nearest. If we can round only one
+ // way, do it. If we can't round, continue the loop.
+ if (can_round_down) {
+ if (can_round_up) {
+ wuffs_base__private_implementation__high_prec_dec__round_nearest(
+ h, hi + 1);
+ return;
+ } else {
+ wuffs_base__private_implementation__high_prec_dec__round_down(h,
+ hi + 1);
+ return;
+ }
+ } else {
+ if (can_round_up) {
+ wuffs_base__private_implementation__high_prec_dec__round_up(h, hi + 1);
+ return;
+ }
+ }
+ }
+}
+
// --------
// The wuffs_base__private_implementation__etc_powers_of_10 tables were printed
@@ -10087,6 +10483,303 @@
} while (0);
}
+// --------
+
+static inline size_t //
+wuffs_base__private_implementation__render_inf(wuffs_base__slice_u8 dst,
+ bool neg,
+ uint32_t options) {
+ if (neg) {
+ if (dst.len < 4) {
+ return 0;
+ }
+ wuffs_base__store_u32le__no_bounds_check(dst.ptr, 0x666E492D); // '-Inf'le.
+ return 4;
+ }
+
+ if (options & WUFFS_BASE__RENDER_NUMBER_XXX__LEADING_PLUS_SIGN) {
+ if (dst.len < 4) {
+ return 0;
+ }
+ wuffs_base__store_u32le__no_bounds_check(dst.ptr, 0x666E492B); // '+Inf'le.
+ return 4;
+ }
+
+ if (dst.len < 3) {
+ return 0;
+ }
+ wuffs_base__store_u24le__no_bounds_check(dst.ptr, 0x666E49); // 'Inf'le.
+ return 3;
+}
+
+static inline size_t //
+wuffs_base__private_implementation__render_nan(wuffs_base__slice_u8 dst) {
+ if (dst.len < 3) {
+ return 0;
+ }
+ wuffs_base__store_u24le__no_bounds_check(dst.ptr, 0x4E614E); // 'NaN'le.
+ return 3;
+}
+
+static size_t //
+wuffs_base__private_implementation__high_prec_dec__render_exponent_absent(
+ wuffs_base__slice_u8 dst,
+ wuffs_base__private_implementation__high_prec_dec* h,
+ uint32_t precision,
+ uint32_t options) {
+ size_t n = (h->negative ||
+ (options & WUFFS_BASE__RENDER_NUMBER_XXX__LEADING_PLUS_SIGN))
+ ? 1
+ : 0;
+ if (h->decimal_point <= 0) {
+ n += 1;
+ } else {
+ n += (size_t)(h->decimal_point);
+ }
+ if (precision > 0) {
+ n += precision + 1; // +1 for the '.'.
+ }
+
+ // Don't modify dst if the formatted number won't fit.
+ if (n > dst.len) {
+ return 0;
+ }
+
+ // Align-left or align-right.
+ uint8_t* ptr = (options & WUFFS_BASE__RENDER_NUMBER_XXX__ALIGN_RIGHT)
+ ? &dst.ptr[dst.len - n]
+ : &dst.ptr[0];
+
+ // Leading "±".
+ if (h->negative) {
+ *ptr++ = '-';
+ } else if (options & WUFFS_BASE__RENDER_NUMBER_XXX__LEADING_PLUS_SIGN) {
+ *ptr++ = '+';
+ }
+
+ // Integral digits.
+ if (h->decimal_point <= 0) {
+ *ptr++ = '0';
+ } else {
+ uint32_t m =
+ wuffs_base__u32__min(h->num_digits, (uint32_t)(h->decimal_point));
+ uint32_t i = 0;
+ for (; i < m; i++) {
+ *ptr++ = (uint8_t)('0' | h->digits[i]);
+ }
+ for (; i < (uint32_t)(h->decimal_point); i++) {
+ *ptr++ = '0';
+ }
+ }
+
+ // Separator and then fractional digits.
+ if (precision > 0) {
+ *ptr++ =
+ (options & WUFFS_BASE__RENDER_NUMBER_FXX__DECIMAL_SEPARATOR_IS_A_COMMA)
+ ? ','
+ : '.';
+ uint32_t i = 0;
+ for (; i < precision; i++) {
+ uint32_t j = ((uint32_t)(h->decimal_point)) + i;
+ *ptr++ = (uint8_t)('0' | ((j < h->num_digits) ? h->digits[j] : 0));
+ }
+ }
+
+ return n;
+}
+
+static size_t //
+wuffs_base__private_implementation__high_prec_dec__render_exponent_present(
+ wuffs_base__slice_u8 dst,
+ wuffs_base__private_implementation__high_prec_dec* h,
+ uint32_t precision,
+ uint32_t options) {
+ int32_t exp = 0;
+ if (h->num_digits > 0) {
+ exp = h->decimal_point - 1;
+ }
+ bool negative_exp = exp < 0;
+ if (negative_exp) {
+ exp = -exp;
+ }
+
+ size_t n = (h->negative ||
+ (options & WUFFS_BASE__RENDER_NUMBER_XXX__LEADING_PLUS_SIGN))
+ ? 4
+ : 3; // Mininum 3 bytes: first digit and then "e±".
+ if (precision > 0) {
+ n += precision + 1; // +1 for the '.'.
+ }
+ n += (exp < 100) ? 2 : 3;
+
+ // Don't modify dst if the formatted number won't fit.
+ if (n > dst.len) {
+ return 0;
+ }
+
+ // Align-left or align-right.
+ uint8_t* ptr = (options & WUFFS_BASE__RENDER_NUMBER_XXX__ALIGN_RIGHT)
+ ? &dst.ptr[dst.len - n]
+ : &dst.ptr[0];
+
+ // Leading "±".
+ if (h->negative) {
+ *ptr++ = '-';
+ } else if (options & WUFFS_BASE__RENDER_NUMBER_XXX__LEADING_PLUS_SIGN) {
+ *ptr++ = '+';
+ }
+
+ // Integral digit.
+ if (h->num_digits > 0) {
+ *ptr++ = (uint8_t)('0' | h->digits[0]);
+ } else {
+ *ptr++ = '0';
+ }
+
+ // Separator and then fractional digits.
+ if (precision > 0) {
+ *ptr++ =
+ (options & WUFFS_BASE__RENDER_NUMBER_FXX__DECIMAL_SEPARATOR_IS_A_COMMA)
+ ? ','
+ : '.';
+ uint32_t i = 1;
+ uint32_t j = wuffs_base__u32__min(h->num_digits, precision + 1);
+ for (; i < j; i++) {
+ *ptr++ = (uint8_t)('0' | h->digits[i]);
+ }
+ for (; i <= precision; i++) {
+ *ptr++ = '0';
+ }
+ }
+
+ // Exponent: "e±" and then 2 or 3 digits.
+ *ptr++ = 'e';
+ *ptr++ = negative_exp ? '-' : '+';
+ if (exp < 10) {
+ *ptr++ = '0';
+ *ptr++ = (uint8_t)('0' | exp);
+ } else if (exp < 100) {
+ *ptr++ = (uint8_t)('0' | (exp / 10));
+ *ptr++ = (uint8_t)('0' | (exp % 10));
+ } else {
+ int32_t e = exp / 100;
+ exp -= e * 100;
+ *ptr++ = (uint8_t)('0' | e);
+ *ptr++ = (uint8_t)('0' | (exp / 10));
+ *ptr++ = (uint8_t)('0' | (exp % 10));
+ }
+
+ return n;
+}
+
+WUFFS_BASE__MAYBE_STATIC size_t //
+wuffs_base__render_number_f64(wuffs_base__slice_u8 dst,
+ double x,
+ uint32_t precision,
+ uint32_t options) {
+ // Decompose x (64 bits) into negativity (1 bit), base-2 exponent (11 bits
+ // with a -1023 bias) and mantissa (52 bits).
+ uint64_t bits = wuffs_base__ieee_754_bit_representation__from_f64(x);
+ bool neg = (bits >> 63) != 0;
+ int32_t exp2 = ((int32_t)(bits >> 52)) & 0x7FF;
+ uint64_t man = bits & 0x000FFFFFFFFFFFFFul;
+
+ // Apply the exponent bias and set the implicit top bit of the mantissa,
+ // unless x is subnormal. Also take care of Inf and NaN.
+ if (exp2 == 0x7FF) {
+ if (man != 0) {
+ return wuffs_base__private_implementation__render_nan(dst);
+ }
+ return wuffs_base__private_implementation__render_inf(dst, neg, options);
+ } else if (exp2 == 0) {
+ exp2 = -1022;
+ } else {
+ exp2 -= 1023;
+ man |= 0x0010000000000000ul;
+ }
+
+ // Ensure that precision isn't too large.
+ if (precision > 4095) {
+ precision = 4095;
+ }
+
+ // Convert from the (neg, exp2, man) tuple to an HPD.
+ wuffs_base__private_implementation__high_prec_dec h;
+ wuffs_base__private_implementation__high_prec_dec__assign(&h, man, neg);
+ if (h.num_digits > 0) {
+ wuffs_base__private_implementation__high_prec_dec__lshift(
+ &h, exp2 - 52); // 52 mantissa bits.
+ }
+
+ // Handle the "%e" and "%f" formats.
+ switch (options & (WUFFS_BASE__RENDER_NUMBER_FXX__EXPONENT_ABSENT |
+ WUFFS_BASE__RENDER_NUMBER_FXX__EXPONENT_PRESENT)) {
+ case WUFFS_BASE__RENDER_NUMBER_FXX__EXPONENT_ABSENT: // The "%"f" format.
+ if (options & WUFFS_BASE__RENDER_NUMBER_FXX__JUST_ENOUGH_PRECISION) {
+ wuffs_base__private_implementation__high_prec_dec__round_just_enough(
+ &h, exp2, man);
+ int32_t p = ((int32_t)(h.num_digits)) - h.decimal_point;
+ precision = ((uint32_t)(wuffs_base__i32__max(0, p)));
+ } else {
+ wuffs_base__private_implementation__high_prec_dec__round_nearest(
+ &h, ((int32_t)precision) + h.decimal_point);
+ }
+ return wuffs_base__private_implementation__high_prec_dec__render_exponent_absent(
+ dst, &h, precision, options);
+
+ case WUFFS_BASE__RENDER_NUMBER_FXX__EXPONENT_PRESENT: // The "%e" format.
+ if (options & WUFFS_BASE__RENDER_NUMBER_FXX__JUST_ENOUGH_PRECISION) {
+ wuffs_base__private_implementation__high_prec_dec__round_just_enough(
+ &h, exp2, man);
+ precision = (h.num_digits > 0) ? (h.num_digits - 1) : 0;
+ } else {
+ wuffs_base__private_implementation__high_prec_dec__round_nearest(
+ &h, ((int32_t)precision) + 1);
+ }
+ return wuffs_base__private_implementation__high_prec_dec__render_exponent_present(
+ dst, &h, precision, options);
+ }
+
+ // We have the "%g" format and so precision means the number of significant
+ // digits, not the number of digits after the decimal separator. Perform
+ // rounding and determine whether to use "%e" or "%f".
+ int32_t e_threshold = 0;
+ if (options & WUFFS_BASE__RENDER_NUMBER_FXX__JUST_ENOUGH_PRECISION) {
+ wuffs_base__private_implementation__high_prec_dec__round_just_enough(
+ &h, exp2, man);
+ precision = h.num_digits;
+ e_threshold = 6;
+ } else {
+ if (precision == 0) {
+ precision = 1;
+ }
+ wuffs_base__private_implementation__high_prec_dec__round_nearest(
+ &h, ((int32_t)precision));
+ e_threshold = ((int32_t)precision);
+ int32_t nd = ((int32_t)(h.num_digits));
+ if ((e_threshold > nd) && (nd >= h.decimal_point)) {
+ e_threshold = nd;
+ }
+ }
+
+ // Use the "%e" format if the exponent is large.
+ int32_t e = h.decimal_point - 1;
+ if ((e < -4) || (e_threshold <= e)) {
+ uint32_t p = wuffs_base__u32__min(precision, h.num_digits);
+ return wuffs_base__private_implementation__high_prec_dec__render_exponent_present(
+ dst, &h, (p > 0) ? (p - 1) : 0, options);
+ }
+
+ // Use the "%f" format otherwise.
+ int32_t p = ((int32_t)precision);
+ if (p > h.decimal_point) {
+ p = ((int32_t)(h.num_digits));
+ }
+ precision = ((uint32_t)(wuffs_base__i32__max(0, p - h.decimal_point)));
+ return wuffs_base__private_implementation__high_prec_dec__render_exponent_absent(
+ dst, &h, precision, options);
+}
+
#endif // !defined(WUFFS_CONFIG__MODULES) ||
// defined(WUFFS_CONFIG__MODULE__BASE) ||
// defined(WUFFS_CONFIG__MODULE__BASE__F64CONV)
@@ -10439,7 +11132,7 @@
if (neg) {
ptr -= 1;
ptr[0] = '-';
- } else if (options & WUFFS_BASE__RENDER_NUMBER__LEADING_PLUS_SIGN) {
+ } else if (options & WUFFS_BASE__RENDER_NUMBER_XXX__LEADING_PLUS_SIGN) {
ptr -= 1;
ptr[0] = '+';
}
@@ -10448,7 +11141,7 @@
if (n > dst.len) {
return 0;
}
- memcpy(dst.ptr + ((options & WUFFS_BASE__RENDER_NUMBER__ALIGN_RIGHT)
+ memcpy(dst.ptr + ((options & WUFFS_BASE__RENDER_NUMBER_XXX__ALIGN_RIGHT)
? (dst.len - n)
: 0),
ptr, n);
diff --git a/script/print-render-number-f64-tests.go b/script/print-render-number-f64-tests.go
new file mode 100644
index 0000000..b4aec2b
--- /dev/null
+++ b/script/print-render-number-f64-tests.go
@@ -0,0 +1,176 @@
+// Copyright 2020 The Wuffs Authors.
+//
+// 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
+//
+// https://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.
+
+// +build ignore
+
+package main
+
+// print-render-number-f64-tests.go prints the
+// test_wuffs_strconv_render_number_f64 test cases.
+//
+// Usage: go run print-render-number-f64-tests.go
+
+import (
+ "fmt"
+ "math"
+ "os"
+ "sort"
+ "strconv"
+)
+
+func main() {
+ if err := main1(); err != nil {
+ os.Stderr.WriteString(err.Error() + "\n")
+ os.Exit(1)
+ }
+}
+
+func main1() error {
+ testCases := append([]uint64(nil), u64TestCases...)
+ for _, f := range f64TestCases {
+ testCases = append(testCases, math.Float64bits(f))
+ }
+
+ sort.Slice(testCases, func(i int, j int) bool {
+ return testCases[i] < testCases[j]
+ })
+
+ for i, tc := range testCases {
+ f := math.Float64frombits(tc)
+
+ if (i > 0) && (tc == testCases[i-1]) {
+ return fmt.Errorf("duplicate test case (f=%g, tc=0x%X)", f, tc)
+ }
+
+ // Check that calling strconv.FormatFloat with a precision of -1 (round
+ // to shortest) does indeed return a string that, when parsed, recovers
+ // the original number.
+ shortest := strconv.FormatFloat(f, 'g', -1, 64)
+ g, err := strconv.ParseFloat(shortest, 64)
+ if err != nil {
+ return fmt.Errorf("ParseFloat failed (f=%g, tc=0x%X): %v", f, tc, err)
+ }
+ equal := tc == math.Float64bits(g)
+ if math.IsNaN(f) {
+ equal = math.IsNaN(g)
+ }
+ if !equal {
+ return fmt.Errorf("round-trip failed (f=%g, tc=0x%X)", f, tc)
+ }
+ }
+
+ for _, tc := range testCases {
+ f := math.Float64frombits(tc)
+ fmt.Printf(`{
+ .x = 0x%016X,
+ .want__e = %s,
+ .want__f = %s,
+ .want_0g = %s,
+ .want_2e = %s,
+ .want_3f = %s,
+ .want_4g = %s,
+},`+"\n",
+ tc,
+ do(f, -1, 'e'),
+ do(f, -1, 'f'),
+ do(f, +0, 'g'),
+ do(f, +2, 'e'),
+ do(f, +3, 'f'),
+ do(f, +4, 'g'),
+ )
+ }
+ return nil
+}
+
+func do(f float64, precision int, format byte) (ret string) {
+ s := strconv.FormatFloat(f, format, precision, 64)
+ for ; len(s) > 50; s = s[50:] {
+ ret += fmt.Sprintf("%q\n\t\t", s[:50])
+ }
+ ret += fmt.Sprintf("%q", s)
+ if ret == `"+Inf"` {
+ ret = `"Inf"`
+ }
+ return ret
+}
+
+var f64TestCases = []float64{
+ // Approximations of e, the base of the natural logarithm.
+ 2.7,
+ 2.72,
+ 2.718,
+ 2.7183,
+ 2.71828,
+ 2.718282,
+ 2.7182818,
+ 2.71828183,
+
+ // Approximations of N_A, the Avogadro constant.
+ 6.0e23,
+ 6.02e23,
+ 6.022e23,
+ 6.0221e23,
+ 6.02214e23,
+ 6.022141e23,
+ 6.0221408e23,
+ 6.02214076e23,
+}
+
+var u64TestCases = []uint64{
+ 0x0000000000000000,
+ 0x0000000000000001,
+ 0x0000000000000002,
+ 0x0000000000000003,
+ 0x000FFFFFFFFFFFFF,
+ 0x0010000000000000,
+ 0x369C314ABE948EB1,
+ 0x3F88000000000000,
+ 0x3FD0000000000000,
+ 0x3FD3333333333333,
+ 0x3FD3333333333334,
+ 0x3FD5555555555555,
+ 0x3FEFFFFFFFFFFFFF,
+ 0x3FF0000000000000,
+ 0x3FF0000000000001,
+ 0x3FF0000000000002,
+ 0x3FF4000000000000,
+ 0x3FF8000000000000,
+ 0x4008000000000000,
+ 0x400921F9F01B866E,
+ 0x400921FB54442D11,
+ 0x400921FB54442D18,
+ 0x400C000000000000,
+ 0x4014000000000000,
+ 0x4036000000000000,
+ 0x4037000000000000,
+ 0x4038000000000000,
+ 0x40FE240C9FCB0C02,
+ 0x4202A05F20000000,
+ 0x4330000000000000,
+ 0x4330000000000001,
+ 0x4330000000000002,
+ 0x4340000000000000,
+ 0x4340000000000001,
+ 0x4340000000000002,
+ 0x4415AF1D78B58C40,
+ 0x46293E5939A08CEA,
+ 0x54B249AD2594C37D,
+ 0x7FEFFFFFFFFFFFFF,
+ 0x7FF0000000000000,
+ 0x7FFFFFFFFFFFFFFF,
+ 0x8000000000000000,
+ 0xC008000000000000,
+ 0xFFF0000000000000,
+ 0xFFFFFFFFFFFFFFFF,
+}
diff --git a/test/c/std/json.c b/test/c/std/json.c
index bb5d967..4bd4834 100644
--- a/test/c/std/json.c
+++ b/test/c/std/json.c
@@ -607,11 +607,16 @@
uint64_t want;
const char* str;
} test_cases[] = {
+ // If adding new cases, consider updating u64TestCases in
+ // script/print-render-number-f64-tests.go
+
{.want = 0x0000000000000000, .str = "+0.0"},
{.want = 0x0000000000000000, .str = "0"},
{.want = 0x0000000000000000, .str = "0e0"},
{.want = 0x0000000000000000, .str = "1e-332"},
{.want = 0x0000000000000001, .str = "4.9406564584124654e-324"},
+ {.want = 0x0000000000000002, .str = "9.8813129168249309e-324"},
+ {.want = 0x0000000000000003, .str = "1.4821969375237396e-323"},
{.want = 0x000FFFFFFFFFFFFF, .str = "2.2250738585072009E-308"},
{.want = 0x0010000000000000, .str = "2.2250738585072014E-308"},
{.want = 0x369C314ABE948EB1,
@@ -679,6 +684,9 @@
{.want = 0xFFF0000000000000, .str = "-inf"},
{.want = 0xFFFFFFFFFFFFFFFF, .str = "-NAN"},
+ // If adding new cases, consider updating u64TestCases in
+ // script/print-render-number-f64-tests.go
+
// We accept either ',' or '.'.
{.want = 0x3FFC000000000000, .str = "1,75"},
{.want = 0x3FFC000000000000, .str = "1.75"},
@@ -859,6 +867,702 @@
}
const char* //
+test_wuffs_strconv_render_number_f64() {
+ CHECK_FOCUS(__func__);
+
+ struct {
+ uint64_t x;
+ // These want strings come from Go's strconv.FormatFloat.
+ const char* want__e; // FormatFloat(etc, 'e', -1, etc)
+ const char* want__f; // FormatFloat(etc, 'f', -1, etc)
+ const char* want_0g; // FormatFloat(etc, 'g', +0, etc)
+ const char* want_2e; // FormatFloat(etc, 'e', +2, etc)
+ const char* want_3f; // FormatFloat(etc, 'f', +3, etc)
+ const char* want_4g; // FormatFloat(etc, 'g', +4, etc)
+ } test_cases[] = {
+ // These test cases were generated by
+ // script/print-render-number-f64-tests.go
+
+ {
+ .x = 0x0000000000000000,
+ .want__e = "0e+00",
+ .want__f = "0",
+ .want_0g = "0",
+ .want_2e = "0.00e+00",
+ .want_3f = "0.000",
+ .want_4g = "0",
+ },
+ {
+ .x = 0x0000000000000001,
+ .want__e = "5e-324",
+ .want__f = "0.000000000000000000000000000000000000000000000000"
+ "00000000000000000000000000000000000000000000000000"
+ "00000000000000000000000000000000000000000000000000"
+ "00000000000000000000000000000000000000000000000000"
+ "00000000000000000000000000000000000000000000000000"
+ "00000000000000000000000000000000000000000000000000"
+ "00000000000000000000000005",
+ .want_0g = "5e-324",
+ .want_2e = "4.94e-324",
+ .want_3f = "0.000",
+ .want_4g = "4.941e-324",
+ },
+ {
+ .x = 0x0000000000000002,
+ .want__e = "1e-323",
+ .want__f = "0.000000000000000000000000000000000000000000000000"
+ "00000000000000000000000000000000000000000000000000"
+ "00000000000000000000000000000000000000000000000000"
+ "00000000000000000000000000000000000000000000000000"
+ "00000000000000000000000000000000000000000000000000"
+ "00000000000000000000000000000000000000000000000000"
+ "0000000000000000000000001",
+ .want_0g = "1e-323",
+ .want_2e = "9.88e-324",
+ .want_3f = "0.000",
+ .want_4g = "9.881e-324",
+ },
+ {
+ .x = 0x0000000000000003,
+ .want__e = "1.5e-323",
+ .want__f = "0.000000000000000000000000000000000000000000000000"
+ "00000000000000000000000000000000000000000000000000"
+ "00000000000000000000000000000000000000000000000000"
+ "00000000000000000000000000000000000000000000000000"
+ "00000000000000000000000000000000000000000000000000"
+ "00000000000000000000000000000000000000000000000000"
+ "00000000000000000000000015",
+ .want_0g = "1e-323",
+ .want_2e = "1.48e-323",
+ .want_3f = "0.000",
+ .want_4g = "1.482e-323",
+ },
+ {
+ .x = 0x000FFFFFFFFFFFFF,
+ .want__e = "2.225073858507201e-308",
+ .want__f = "0.000000000000000000000000000000000000000000000000"
+ "00000000000000000000000000000000000000000000000000"
+ "00000000000000000000000000000000000000000000000000"
+ "00000000000000000000000000000000000000000000000000"
+ "00000000000000000000000000000000000000000000000000"
+ "00000000000000000000000000000000000000000000000000"
+ "0000000002225073858507201",
+ .want_0g = "2e-308",
+ .want_2e = "2.23e-308",
+ .want_3f = "0.000",
+ .want_4g = "2.225e-308",
+ },
+ {
+ .x = 0x0010000000000000,
+ .want__e = "2.2250738585072014e-308",
+ .want__f = "0.000000000000000000000000000000000000000000000000"
+ "00000000000000000000000000000000000000000000000000"
+ "00000000000000000000000000000000000000000000000000"
+ "00000000000000000000000000000000000000000000000000"
+ "00000000000000000000000000000000000000000000000000"
+ "00000000000000000000000000000000000000000000000000"
+ "00000000022250738585072014",
+ .want_0g = "2e-308",
+ .want_2e = "2.23e-308",
+ .want_3f = "0.000",
+ .want_4g = "2.225e-308",
+ },
+ {
+ .x = 0x369C314ABE948EB1,
+ .want__e = "1.23456789e-45",
+ .want__f = "0.000000000000000000000000000000000000000000001234"
+ "56789",
+ .want_0g = "1e-45",
+ .want_2e = "1.23e-45",
+ .want_3f = "0.000",
+ .want_4g = "1.235e-45",
+ },
+ {
+ .x = 0x3F88000000000000,
+ .want__e = "1.171875e-02",
+ .want__f = "0.01171875",
+ .want_0g = "0.01",
+ .want_2e = "1.17e-02",
+ .want_3f = "0.012",
+ .want_4g = "0.01172",
+ },
+ {
+ .x = 0x3FD0000000000000,
+ .want__e = "2.5e-01",
+ .want__f = "0.25",
+ .want_0g = "0.2",
+ .want_2e = "2.50e-01",
+ .want_3f = "0.250",
+ .want_4g = "0.25",
+ },
+ {
+ .x = 0x3FD3333333333333,
+ .want__e = "3e-01",
+ .want__f = "0.3",
+ .want_0g = "0.3",
+ .want_2e = "3.00e-01",
+ .want_3f = "0.300",
+ .want_4g = "0.3",
+ },
+ {
+ .x = 0x3FD3333333333334,
+ .want__e = "3.0000000000000004e-01",
+ .want__f = "0.30000000000000004",
+ .want_0g = "0.3",
+ .want_2e = "3.00e-01",
+ .want_3f = "0.300",
+ .want_4g = "0.3",
+ },
+ {
+ .x = 0x3FD5555555555555,
+ .want__e = "3.333333333333333e-01",
+ .want__f = "0.3333333333333333",
+ .want_0g = "0.3",
+ .want_2e = "3.33e-01",
+ .want_3f = "0.333",
+ .want_4g = "0.3333",
+ },
+ {
+ .x = 0x3FEFFFFFFFFFFFFF,
+ .want__e = "9.999999999999999e-01",
+ .want__f = "0.9999999999999999",
+ .want_0g = "1",
+ .want_2e = "1.00e+00",
+ .want_3f = "1.000",
+ .want_4g = "1",
+ },
+ {
+ .x = 0x3FF0000000000000,
+ .want__e = "1e+00",
+ .want__f = "1",
+ .want_0g = "1",
+ .want_2e = "1.00e+00",
+ .want_3f = "1.000",
+ .want_4g = "1",
+ },
+ {
+ .x = 0x3FF0000000000001,
+ .want__e = "1.0000000000000002e+00",
+ .want__f = "1.0000000000000002",
+ .want_0g = "1",
+ .want_2e = "1.00e+00",
+ .want_3f = "1.000",
+ .want_4g = "1",
+ },
+ {
+ .x = 0x3FF0000000000002,
+ .want__e = "1.0000000000000004e+00",
+ .want__f = "1.0000000000000004",
+ .want_0g = "1",
+ .want_2e = "1.00e+00",
+ .want_3f = "1.000",
+ .want_4g = "1",
+ },
+ {
+ .x = 0x3FF4000000000000,
+ .want__e = "1.25e+00",
+ .want__f = "1.25",
+ .want_0g = "1",
+ .want_2e = "1.25e+00",
+ .want_3f = "1.250",
+ .want_4g = "1.25",
+ },
+ {
+ .x = 0x3FF8000000000000,
+ .want__e = "1.5e+00",
+ .want__f = "1.5",
+ .want_0g = "2",
+ .want_2e = "1.50e+00",
+ .want_3f = "1.500",
+ .want_4g = "1.5",
+ },
+ {
+ .x = 0x400599999999999A,
+ .want__e = "2.7e+00",
+ .want__f = "2.7",
+ .want_0g = "3",
+ .want_2e = "2.70e+00",
+ .want_3f = "2.700",
+ .want_4g = "2.7",
+ },
+ {
+ .x = 0x4005BE76C8B43958,
+ .want__e = "2.718e+00",
+ .want__f = "2.718",
+ .want_0g = "3",
+ .want_2e = "2.72e+00",
+ .want_3f = "2.718",
+ .want_4g = "2.718",
+ },
+ {
+ .x = 0x4005BF0995AAF790,
+ .want__e = "2.71828e+00",
+ .want__f = "2.71828",
+ .want_0g = "3",
+ .want_2e = "2.72e+00",
+ .want_3f = "2.718",
+ .want_4g = "2.718",
+ },
+ {
+ .x = 0x4005BF0A87427F01,
+ .want__e = "2.7182818e+00",
+ .want__f = "2.7182818",
+ .want_0g = "3",
+ .want_2e = "2.72e+00",
+ .want_3f = "2.718",
+ .want_4g = "2.718",
+ },
+ {
+ .x = 0x4005BF0A8B4949CB,
+ .want__e = "2.71828183e+00",
+ .want__f = "2.71828183",
+ .want_0g = "3",
+ .want_2e = "2.72e+00",
+ .want_3f = "2.718",
+ .want_4g = "2.718",
+ },
+ {
+ .x = 0x4005BF0AA21A719B,
+ .want__e = "2.718282e+00",
+ .want__f = "2.718282",
+ .want_0g = "3",
+ .want_2e = "2.72e+00",
+ .want_3f = "2.718",
+ .want_4g = "2.718",
+ },
+ {
+ .x = 0x4005BF141205BC02,
+ .want__e = "2.7183e+00",
+ .want__f = "2.7183",
+ .want_0g = "3",
+ .want_2e = "2.72e+00",
+ .want_3f = "2.718",
+ .want_4g = "2.718",
+ },
+ {
+ .x = 0x4005C28F5C28F5C3,
+ .want__e = "2.72e+00",
+ .want__f = "2.72",
+ .want_0g = "3",
+ .want_2e = "2.72e+00",
+ .want_3f = "2.720",
+ .want_4g = "2.72",
+ },
+ {
+ .x = 0x4008000000000000,
+ .want__e = "3e+00",
+ .want__f = "3",
+ .want_0g = "3",
+ .want_2e = "3.00e+00",
+ .want_3f = "3.000",
+ .want_4g = "3",
+ },
+ {
+ .x = 0x400921F9F01B866E,
+ .want__e = "3.14159e+00",
+ .want__f = "3.14159",
+ .want_0g = "3",
+ .want_2e = "3.14e+00",
+ .want_3f = "3.142",
+ .want_4g = "3.142",
+ },
+ {
+ .x = 0x400921FB54442D11,
+ .want__e = "3.14159265358979e+00",
+ .want__f = "3.14159265358979",
+ .want_0g = "3",
+ .want_2e = "3.14e+00",
+ .want_3f = "3.142",
+ .want_4g = "3.142",
+ },
+ {
+ .x = 0x400921FB54442D18,
+ .want__e = "3.141592653589793e+00",
+ .want__f = "3.141592653589793",
+ .want_0g = "3",
+ .want_2e = "3.14e+00",
+ .want_3f = "3.142",
+ .want_4g = "3.142",
+ },
+ {
+ .x = 0x400C000000000000,
+ .want__e = "3.5e+00",
+ .want__f = "3.5",
+ .want_0g = "4",
+ .want_2e = "3.50e+00",
+ .want_3f = "3.500",
+ .want_4g = "3.5",
+ },
+ {
+ .x = 0x4014000000000000,
+ .want__e = "5e+00",
+ .want__f = "5",
+ .want_0g = "5",
+ .want_2e = "5.00e+00",
+ .want_3f = "5.000",
+ .want_4g = "5",
+ },
+ {
+ .x = 0x4036000000000000,
+ .want__e = "2.2e+01",
+ .want__f = "22",
+ .want_0g = "2e+01",
+ .want_2e = "2.20e+01",
+ .want_3f = "22.000",
+ .want_4g = "22",
+ },
+ {
+ .x = 0x4037000000000000,
+ .want__e = "2.3e+01",
+ .want__f = "23",
+ .want_0g = "2e+01",
+ .want_2e = "2.30e+01",
+ .want_3f = "23.000",
+ .want_4g = "23",
+ },
+ {
+ .x = 0x4038000000000000,
+ .want__e = "2.4e+01",
+ .want__f = "24",
+ .want_0g = "2e+01",
+ .want_2e = "2.40e+01",
+ .want_3f = "24.000",
+ .want_4g = "24",
+ },
+ {
+ .x = 0x40FE240C9FCB0C02,
+ .want__e = "1.23456789012e+05",
+ .want__f = "123456.789012",
+ .want_0g = "1e+05",
+ .want_2e = "1.23e+05",
+ .want_3f = "123456.789",
+ .want_4g = "1.235e+05",
+ },
+ {
+ .x = 0x4202A05F20000000,
+ .want__e = "1e+10",
+ .want__f = "10000000000",
+ .want_0g = "1e+10",
+ .want_2e = "1.00e+10",
+ .want_3f = "10000000000.000",
+ .want_4g = "1e+10",
+ },
+ {
+ .x = 0x4330000000000000,
+ .want__e = "4.503599627370496e+15",
+ .want__f = "4503599627370496",
+ .want_0g = "5e+15",
+ .want_2e = "4.50e+15",
+ .want_3f = "4503599627370496.000",
+ .want_4g = "4.504e+15",
+ },
+ {
+ .x = 0x4330000000000001,
+ .want__e = "4.503599627370497e+15",
+ .want__f = "4503599627370497",
+ .want_0g = "5e+15",
+ .want_2e = "4.50e+15",
+ .want_3f = "4503599627370497.000",
+ .want_4g = "4.504e+15",
+ },
+ {
+ .x = 0x4330000000000002,
+ .want__e = "4.503599627370498e+15",
+ .want__f = "4503599627370498",
+ .want_0g = "5e+15",
+ .want_2e = "4.50e+15",
+ .want_3f = "4503599627370498.000",
+ .want_4g = "4.504e+15",
+ },
+ {
+ .x = 0x4340000000000000,
+ .want__e = "9.007199254740992e+15",
+ .want__f = "9007199254740992",
+ .want_0g = "9e+15",
+ .want_2e = "9.01e+15",
+ .want_3f = "9007199254740992.000",
+ .want_4g = "9.007e+15",
+ },
+ {
+ .x = 0x4340000000000001,
+ .want__e = "9.007199254740994e+15",
+ .want__f = "9007199254740994",
+ .want_0g = "9e+15",
+ .want_2e = "9.01e+15",
+ .want_3f = "9007199254740994.000",
+ .want_4g = "9.007e+15",
+ },
+ {
+ .x = 0x4340000000000002,
+ .want__e = "9.007199254740996e+15",
+ .want__f = "9007199254740996",
+ .want_0g = "9e+15",
+ .want_2e = "9.01e+15",
+ .want_3f = "9007199254740996.000",
+ .want_4g = "9.007e+15",
+ },
+ {
+ .x = 0x4415AF1D78B58C40,
+ .want__e = "1e+20",
+ .want__f = "100000000000000000000",
+ .want_0g = "1e+20",
+ .want_2e = "1.00e+20",
+ .want_3f = "100000000000000000000.000",
+ .want_4g = "1e+20",
+ },
+ {
+ .x = 0x44DFC3842BD1F072,
+ .want__e = "6e+23",
+ .want__f = "600000000000000000000000",
+ .want_0g = "6e+23",
+ .want_2e = "6.00e+23",
+ .want_3f = "600000000000000016777216.000",
+ .want_4g = "6e+23",
+ },
+ {
+ .x = 0x44DFDE9F10A8D361,
+ .want__e = "6.02e+23",
+ .want__f = "602000000000000000000000",
+ .want_0g = "6e+23",
+ .want_2e = "6.02e+23",
+ .want_3f = "601999999999999995805696.000",
+ .want_4g = "6.02e+23",
+ },
+ {
+ .x = 0x44DFE154F457EA13,
+ .want__e = "6.022e+23",
+ .want__f = "602200000000000000000000",
+ .want_0g = "6e+23",
+ .want_2e = "6.02e+23",
+ .want_3f = "602200000000000027262976.000",
+ .want_4g = "6.022e+23",
+ },
+ {
+ .x = 0x44DFE177A620AB35,
+ .want__e = "6.0221e+23",
+ .want__f = "602210000000000000000000",
+ .want_0g = "6e+23",
+ .want_2e = "6.02e+23",
+ .want_3f = "602209999999999995281408.000",
+ .want_4g = "6.022e+23",
+ },
+ {
+ .x = 0x44DFE18586D75EDC,
+ .want__e = "6.02214e+23",
+ .want__f = "602214000000000000000000",
+ .want_0g = "6e+23",
+ .want_2e = "6.02e+23",
+ .want_3f = "602213999999999969067008.000",
+ .want_4g = "6.022e+23",
+ },
+ {
+ .x = 0x44DFE185CA57C517,
+ .want__e = "6.02214076e+23",
+ .want__f = "602214076000000000000000",
+ .want_0g = "6e+23",
+ .want_2e = "6.02e+23",
+ .want_3f = "602214075999999987023872.000",
+ .want_4g = "6.022e+23",
+ },
+ {
+ .x = 0x44DFE185CDE543BC,
+ .want__e = "6.0221408e+23",
+ .want__f = "602214080000000000000000",
+ .want_0g = "6e+23",
+ .want_2e = "6.02e+23",
+ .want_3f = "602214080000000002097152.000",
+ .want_4g = "6.022e+23",
+ },
+ {
+ .x = 0x44DFE185DFA8BCF4,
+ .want__e = "6.022141e+23",
+ .want__f = "602214100000000000000000",
+ .want_0g = "6e+23",
+ .want_2e = "6.02e+23",
+ .want_3f = "602214100000000010354688.000",
+ .want_4g = "6.022e+23",
+ },
+ {
+ .x = 0x46293E5939A08CEA,
+ .want__e = "1e+30",
+ .want__f = "1000000000000000000000000000000",
+ .want_0g = "1e+30",
+ .want_2e = "1.00e+30",
+ .want_3f = "1000000000000000019884624838656.000",
+ .want_4g = "1e+30",
+ },
+ {
+ .x = 0x54B249AD2594C37D,
+ .want__e = "1e+100",
+ .want__f = "10000000000000000000000000000000000000000000000000"
+ "00000000000000000000000000000000000000000000000000"
+ "0",
+ .want_0g = "1e+100",
+ .want_2e = "1.00e+100",
+ .want_3f = "10000000000000000159028911097599180468360808563945"
+ "28138978132755774783877217038106081346998585681510"
+ "4.000",
+ .want_4g = "1e+100",
+ },
+ {
+ .x = 0x7FEFFFFFFFFFFFFF,
+ .want__e = "1.7976931348623157e+308",
+ .want__f = "17976931348623157000000000000000000000000000000000"
+ "00000000000000000000000000000000000000000000000000"
+ "00000000000000000000000000000000000000000000000000"
+ "00000000000000000000000000000000000000000000000000"
+ "00000000000000000000000000000000000000000000000000"
+ "00000000000000000000000000000000000000000000000000"
+ "000000000",
+ .want_0g = "2e+308",
+ .want_2e = "1.80e+308",
+ .want_3f = "17976931348623157081452742373170435679807056752584"
+ "49965989174768031572607800285387605895586327668781"
+ "71540458953514382464234321326889464182768467546703"
+ "53751698604991057655128207624549009038932894407586"
+ "85084551339423045832369032229481658085593321233482"
+ "74797826204144723168738177180919299881250404026184"
+ "124858368.000",
+ .want_4g = "1.798e+308",
+ },
+ {
+ .x = 0x7FF0000000000000,
+ .want__e = "Inf",
+ .want__f = "Inf",
+ .want_0g = "Inf",
+ .want_2e = "Inf",
+ .want_3f = "Inf",
+ .want_4g = "Inf",
+ },
+ {
+ .x = 0x7FFFFFFFFFFFFFFF,
+ .want__e = "NaN",
+ .want__f = "NaN",
+ .want_0g = "NaN",
+ .want_2e = "NaN",
+ .want_3f = "NaN",
+ .want_4g = "NaN",
+ },
+ {
+ .x = 0x8000000000000000,
+ .want__e = "-0e+00",
+ .want__f = "-0",
+ .want_0g = "-0",
+ .want_2e = "-0.00e+00",
+ .want_3f = "-0.000",
+ .want_4g = "-0",
+ },
+ {
+ .x = 0xC008000000000000,
+ .want__e = "-3e+00",
+ .want__f = "-3",
+ .want_0g = "-3",
+ .want_2e = "-3.00e+00",
+ .want_3f = "-3.000",
+ .want_4g = "-3",
+ },
+ {
+ .x = 0xFFF0000000000000,
+ .want__e = "-Inf",
+ .want__f = "-Inf",
+ .want_0g = "-Inf",
+ .want_2e = "-Inf",
+ .want_3f = "-Inf",
+ .want_4g = "-Inf",
+ },
+ {
+ .x = 0xFFFFFFFFFFFFFFFF,
+ .want__e = "NaN",
+ .want__f = "NaN",
+ .want_0g = "NaN",
+ .want_2e = "NaN",
+ .want_3f = "NaN",
+ .want_4g = "NaN",
+ },
+ };
+
+ int tc;
+ for (tc = 0; tc < WUFFS_TESTLIB_ARRAY_SIZE(test_cases); tc++) {
+ double f64 =
+ wuffs_base__ieee_754_bit_representation__to_f64(test_cases[tc].x);
+ int o;
+ for (o = 0; o < 6; o++) {
+ uint32_t precision = 0;
+ uint32_t options = 0;
+ const char* want = NULL;
+ if (o == 0) {
+ options = WUFFS_BASE__RENDER_NUMBER_FXX__EXPONENT_PRESENT |
+ WUFFS_BASE__RENDER_NUMBER_FXX__JUST_ENOUGH_PRECISION;
+ want = test_cases[tc].want__e;
+ } else if (o == 1) {
+ options = WUFFS_BASE__RENDER_NUMBER_FXX__EXPONENT_ABSENT |
+ WUFFS_BASE__RENDER_NUMBER_FXX__JUST_ENOUGH_PRECISION;
+ want = test_cases[tc].want__f;
+ } else if (o == 2) {
+ precision = 0;
+ options = 0;
+ want = test_cases[tc].want_0g;
+ } else if (o == 3) {
+ precision = 2;
+ options = WUFFS_BASE__RENDER_NUMBER_FXX__EXPONENT_PRESENT;
+ want = test_cases[tc].want_2e;
+ } else if (o == 4) {
+ precision = 3;
+ options = WUFFS_BASE__RENDER_NUMBER_FXX__EXPONENT_ABSENT;
+ want = test_cases[tc].want_3f;
+ } else if (o == 5) {
+ precision = 4;
+ options = 0;
+ want = test_cases[tc].want_4g;
+ }
+
+ size_t n = wuffs_base__render_number_f64(g_have_slice_u8, f64, precision,
+ options);
+ if (n == 0) {
+ RETURN_FAIL("x=0x%016" PRIX64 ", o=%d: could not render",
+ test_cases[tc].x, o);
+ } else if (n >= g_have_slice_u8.len) {
+ RETURN_FAIL("x=0x%016" PRIX64 ", o=%d: n is too large",
+ test_cases[tc].x, o);
+ }
+ g_have_slice_u8.ptr[n] = 0x00;
+ if (strcmp((const char*)(g_have_slice_u8.ptr), want) != 0) {
+ RETURN_FAIL("x=0x%016" PRIX64 ", o=%d: have \"%s\", want \"%s\"",
+ test_cases[tc].x, o, g_have_slice_u8.ptr, want);
+ }
+ }
+ }
+
+ // Test WUFFS_BASE__RENDER_NUMBER_FXX__DECIMAL_SEPARATOR_IS_A_COMMA.
+ {
+ int o;
+ for (o = 0; o < 2; o++) {
+ uint8_t dst[8] = {0};
+ const double f64 = 1.75;
+ const uint32_t precision = 2;
+ size_t n = wuffs_base__render_number_f64(
+ wuffs_base__make_slice_u8(&dst[0], WUFFS_TESTLIB_ARRAY_SIZE(dst)),
+ f64, precision,
+ WUFFS_BASE__RENDER_NUMBER_FXX__EXPONENT_ABSENT |
+ (o ? WUFFS_BASE__RENDER_NUMBER_FXX__DECIMAL_SEPARATOR_IS_A_COMMA
+ : 0));
+ if (n != 4) {
+ RETURN_FAIL("DECIMAL_SEPARATOR_IS_A_COMMA, o=%d: n != 4", o);
+ }
+ uint8_t have = dst[1];
+ uint8_t want = o ? ',' : '.';
+ if (have != want) {
+ RETURN_FAIL(
+ "DECIMAL_SEPARATOR_IS_A_COMMA, o=%d: have 0x%02X, want 0x%02X", o,
+ (int)have, (int)want);
+ }
+ }
+ }
+
+ return NULL;
+}
+
+const char* //
test_wuffs_strconv_render_number_i64() {
CHECK_FOCUS(__func__);
@@ -909,7 +1613,7 @@
for (tc = 0; tc < WUFFS_TESTLIB_ARRAY_SIZE(test_cases); tc++) {
size_t n = wuffs_base__render_number_i64(
g_have_slice_u8, test_cases[tc].x,
- WUFFS_BASE__RENDER_NUMBER__DEFAULT_OPTIONS);
+ WUFFS_BASE__RENDER_NUMBER_XXX__DEFAULT_OPTIONS);
if (n == 0) {
RETURN_FAIL("%" PRId64 ": could not render", test_cases[tc].x);
} else if (n >= g_have_slice_u8.len) {
@@ -964,7 +1668,7 @@
for (tc = 0; tc < WUFFS_TESTLIB_ARRAY_SIZE(test_cases); tc++) {
size_t n = wuffs_base__render_number_u64(
g_have_slice_u8, test_cases[tc].x,
- WUFFS_BASE__RENDER_NUMBER__DEFAULT_OPTIONS);
+ WUFFS_BASE__RENDER_NUMBER_XXX__DEFAULT_OPTIONS);
if (n == 0) {
RETURN_FAIL("%" PRIu64 ": could not render", test_cases[tc].x);
} else if (n >= g_have_slice_u8.len) {
@@ -982,7 +1686,7 @@
uint8_t dst[5];
size_t n = wuffs_base__render_number_u64(
wuffs_base__make_slice_u8(&dst[0], sizeof(dst)), 123456,
- WUFFS_BASE__RENDER_NUMBER__DEFAULT_OPTIONS);
+ WUFFS_BASE__RENDER_NUMBER_XXX__DEFAULT_OPTIONS);
if (n != 0) {
RETURN_FAIL("dst too short: have %zu, want 0", n);
}
@@ -994,8 +1698,8 @@
memcpy(&dst[0], "ABCDEFG\x00", 8);
size_t n = wuffs_base__render_number_u64(
wuffs_base__make_slice_u8(&dst[0], sizeof(dst) - 1), 1234,
- WUFFS_BASE__RENDER_NUMBER__ALIGN_RIGHT |
- WUFFS_BASE__RENDER_NUMBER__LEADING_PLUS_SIGN);
+ WUFFS_BASE__RENDER_NUMBER_XXX__ALIGN_RIGHT |
+ WUFFS_BASE__RENDER_NUMBER_XXX__LEADING_PLUS_SIGN);
if (n != 5) {
RETURN_FAIL("ALIGN_RIGHT | LEADING_PLUS_SIGN: have %zu, want 5", n);
}
@@ -2634,6 +3338,7 @@
test_wuffs_strconv_parse_number_f64,
test_wuffs_strconv_parse_number_i64,
test_wuffs_strconv_parse_number_u64,
+ test_wuffs_strconv_render_number_f64,
test_wuffs_strconv_render_number_i64,
test_wuffs_strconv_render_number_u64,
test_wuffs_strconv_utf_8_next,