Add wuffs_base__parse_number_f64
diff --git a/internal/cgen/base/core-public.h b/internal/cgen/base/core-public.h
index 5277eef..accb01a 100644
--- a/internal/cgen/base/core-public.h
+++ b/internal/cgen/base/core-public.h
@@ -248,6 +248,7 @@
T value; \
}
+typedef WUFFS_BASE__RESULT(double) wuffs_base__result_f64;
typedef WUFFS_BASE__RESULT(int64_t) wuffs_base__result_i64;
typedef WUFFS_BASE__RESULT(uint64_t) wuffs_base__result_u64;
diff --git a/internal/cgen/base/strconv-impl.c b/internal/cgen/base/strconv-impl.c
index 4e2d6e4..1d4dbef 100644
--- a/internal/cgen/base/strconv-impl.c
+++ b/internal/cgen/base/strconv-impl.c
@@ -299,6 +299,811 @@
} while (0);
}
+ // ---------------- IEEE 754 Floating Point
+
+#define WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DECIMAL_POINT__RANGE 1023
+#define WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DIGITS_PRECISION 500
+
+// WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__SHIFT__MAX_INCL is the largest N
+// such that ((10 << N) < (1 << 64)).
+#define WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__SHIFT__MAX_INCL 60
+
+// wuffs_base__private_implementation__high_prec_dec (abbreviated as HPD) is a
+// fixed precision floating point decimal number, augmented with ±infinity
+// values, but it cannot represent NaN (Not a Number).
+//
+// 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
+// WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DIGITS_PRECISION and
+// WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DECIMAL_POINT__RANGE.
+//
+// digits[.. num_digits] are the number's digits in big-endian order. The
+// uint8_t values are in the range [0 ..= 9], not ['0' ..= '9'], where e.g. '7'
+// is the ASCII value 0x37.
+//
+// decimal_point is the index (within digits) of the decimal point. It may be
+// negative or be larger than num_digits, in which case the explicit digits are
+// padded with implicit zeroes.
+//
+// For example, if num_digits is 3 and digits is "\x07\x08\x09":
+// - A decimal_point of -2 means ".00789"
+// - A decimal_point of -1 means ".0789"
+// - A decimal_point of -0 means ".789"
+// - A decimal_point of +1 means "7.89"
+// - A decimal_point of +2 means "78.9"
+// - A decimal_point of +3 means "789."
+// - 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.
+//
+// negative is a sign bit. An HPD can distinguish positive and negative zero.
+//
+// truncated is whether there are more than
+// WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DIGITS_PRECISION digits, and at
+// least one of those extra digits are non-zero. The existence of long-tail
+// digits can affect rounding.
+//
+// The "all fields are zero" value is valid, and represents the number +0.
+typedef struct {
+ uint32_t num_digits;
+ int32_t decimal_point;
+ bool negative;
+ bool truncated;
+ uint8_t digits[WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DIGITS_PRECISION];
+} wuffs_base__private_implementation__high_prec_dec;
+
+// wuffs_base__private_implementation__high_prec_dec__trim trims trailing
+// zeroes from the h->digits[.. h->num_digits] slice. They have no benefit,
+// since we explicitly track h->decimal_point.
+//
+// Preconditions:
+// - h is non-NULL.
+static inline void //
+wuffs_base__private_implementation__high_prec_dec__trim(
+ wuffs_base__private_implementation__high_prec_dec* h) {
+ while ((h->num_digits > 0) && (h->digits[h->num_digits - 1] == 0)) {
+ h->num_digits--;
+ }
+}
+
+static wuffs_base__status //
+wuffs_base__private_implementation__high_prec_dec__parse(
+ wuffs_base__private_implementation__high_prec_dec* h,
+ wuffs_base__slice_u8 s) {
+ if (!h) {
+ return wuffs_base__make_status(wuffs_base__error__bad_receiver);
+ }
+ h->num_digits = 0;
+ h->decimal_point = 0;
+ h->negative = false;
+ h->truncated = false;
+
+ uint8_t* p = s.ptr;
+ uint8_t* q = s.ptr + s.len;
+
+ for (; (p < q) && (*p == '_'); p++) {
+ }
+ if (p >= q) {
+ return wuffs_base__make_status(wuffs_base__error__bad_argument);
+ }
+
+ // Parse sign.
+ do {
+ if (*p == '+') {
+ p++;
+ } else if (*p == '-') {
+ h->negative = true;
+ p++;
+ } else {
+ break;
+ }
+ for (; (p < q) && (*p == '_'); p++) {
+ }
+ } while (0);
+
+ // Parse digits.
+ uint32_t nd = 0;
+ int32_t dp = 0;
+ bool saw_digits = false;
+ bool saw_non_zero_digits = false;
+ bool saw_dot = false;
+ for (; p < q; p++) {
+ if (*p == '_') {
+ // No-op.
+
+ } else if ((*p == '.') || (*p == ',')) {
+ // As per https://en.wikipedia.org/wiki/Decimal_separator, both '.' or
+ // ',' are commonly used. We just parse either, regardless of LOCALE.
+ if (saw_dot) {
+ return wuffs_base__make_status(wuffs_base__error__bad_argument);
+ }
+ saw_dot = true;
+ dp = (int32_t)nd;
+
+ } else if ('0' == *p) {
+ if (!saw_dot && !saw_non_zero_digits && saw_digits) {
+ // We don't allow unnecessary leading zeroes: "000123" or "0644".
+ return wuffs_base__make_status(wuffs_base__error__bad_argument);
+ }
+ saw_digits = true;
+ if (nd == 0) {
+ // Track leading zeroes implicitly.
+ dp--;
+ } else if (nd <
+ WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DIGITS_PRECISION) {
+ h->digits[nd++] = 0;
+ } else {
+ // Long-tail zeroes are ignored.
+ }
+
+ } else if (('0' < *p) && (*p <= '9')) {
+ if (!saw_dot && !saw_non_zero_digits && saw_digits) {
+ // We don't allow unnecessary leading zeroes: "000123" or "0644".
+ return wuffs_base__make_status(wuffs_base__error__bad_argument);
+ }
+ saw_digits = true;
+ saw_non_zero_digits = true;
+ if (nd < WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DIGITS_PRECISION) {
+ h->digits[nd++] = (uint8_t)(*p - '0');
+ } else {
+ // Long-tail non-zeroes set the truncated bit.
+ h->truncated = true;
+ }
+
+ } else {
+ break;
+ }
+ }
+
+ if (!saw_digits) {
+ return wuffs_base__make_status(wuffs_base__error__bad_argument);
+ }
+ if (!saw_dot) {
+ dp = (int32_t)nd;
+ }
+
+ // Parse exponent.
+ if ((p < q) && ((*p == 'E') || (*p == 'e'))) {
+ p++;
+ for (; (p < q) && (*p == '_'); p++) {
+ }
+ if (p >= q) {
+ return wuffs_base__make_status(wuffs_base__error__bad_argument);
+ }
+
+ int32_t exp_sign = +1;
+ if (*p == '+') {
+ p++;
+ } else if (*p == '-') {
+ exp_sign = -1;
+ p++;
+ }
+
+ int32_t exp = 0;
+ const int32_t exp_large =
+ WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DECIMAL_POINT__RANGE +
+ WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DIGITS_PRECISION;
+ bool saw_exp_digits = false;
+ for (; p < q; p++) {
+ if (*p == '_') {
+ // No-op.
+ } else if (('0' <= *p) && (*p <= '9')) {
+ saw_exp_digits = true;
+ if (exp < exp_large) {
+ exp = (10 * exp) + ((int32_t)(*p - '0'));
+ }
+ } else {
+ break;
+ }
+ }
+ if (!saw_exp_digits) {
+ return wuffs_base__make_status(wuffs_base__error__bad_argument);
+ }
+ dp += exp_sign * exp;
+ }
+
+ // Finish.
+ if (p != q) {
+ return wuffs_base__make_status(wuffs_base__error__bad_argument);
+ }
+ h->num_digits = nd;
+ if (nd == 0) {
+ h->decimal_point = 0;
+ } else if (dp <
+ -WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DECIMAL_POINT__RANGE) {
+ h->decimal_point =
+ -WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DECIMAL_POINT__RANGE - 1;
+ } else if (dp >
+ +WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DECIMAL_POINT__RANGE) {
+ h->decimal_point =
+ +WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DECIMAL_POINT__RANGE + 1;
+ } else {
+ h->decimal_point = dp;
+ }
+ wuffs_base__private_implementation__high_prec_dec__trim(h);
+ return wuffs_base__make_status(NULL);
+}
+
+// --------
+
+// The etc__hpd_left_shift and etc__powers_of_5 tables were printed by
+// script/print-hpd-left-shift.go. That script has an optional -comments flag,
+// whose output is not copied here, which prints further detail.
+//
+// These tables are used in
+// wuffs_base__private_implementation__high_prec_dec__lshift_num_new_digits.
+
+// wuffs_base__private_implementation__hpd_left_shift[i] encodes the number of
+// new digits created after multiplying a positive integer by (1 << i): the
+// additional length in the decimal representation. For example, shifting "234"
+// by 3 (equivalent to multiplying by 8) will produce "1872". Going from a
+// 3-length string to a 4-length string means that 1 new digit was added (and
+// existing digits may have changed).
+//
+// Shifting by i can add either N or N-1 new digits, depending on whether the
+// original positive integer compares >= or < to the i'th power of 5 (as 10
+// equals 2 * 5). Comparison is lexicographic, not numerical.
+//
+// For example, shifting by 4 (i.e. multiplying by 16) can add 1 or 2 new
+// digits, depending on a lexicographic comparison to (5 ** 4), i.e. "625":
+// - ("1" << 4) is "16", which adds 1 new digit.
+// - ("5678" << 4) is "90848", which adds 1 new digit.
+// - ("624" << 4) is "9984", which adds 1 new digit.
+// - ("62498" << 4) is "999968", which adds 1 new digit.
+// - ("625" << 4) is "10000", which adds 2 new digits.
+// - ("625001" << 4) is "10000016", which adds 2 new digits.
+// - ("7008" << 4) is "112128", which adds 2 new digits.
+// - ("99" << 4) is "1584", which adds 2 new digits.
+//
+// Thus, when i is 4, N is 2 and (5 ** i) is "625". This etc__hpd_left_shift
+// array encodes this as:
+// - etc__hpd_left_shift[4] is 0x1006 = (2 << 11) | 0x0006.
+// - etc__hpd_left_shift[5] is 0x1009 = (? << 11) | 0x0009.
+// where the ? isn't relevant for i == 4.
+//
+// The high 5 bits of etc__hpd_left_shift[i] is N, the higher of the two
+// possible number of new digits. The low 11 bits are an offset into the
+// etc__powers_of_5 array (of length 0x051C, so offsets fit in 11 bits). When i
+// is 4, its offset and the next one is 6 and 9, and etc__powers_of_5[6 .. 9]
+// is the string "\x06\x02\x05", so the relevant power of 5 is "625".
+//
+// Thanks to Ken Thompson for the original idea.
+static const uint16_t wuffs_base__private_implementation__hpd_left_shift[65] = {
+ 0x0000, 0x0800, 0x0801, 0x0803, 0x1006, 0x1009, 0x100D, 0x1812, 0x1817,
+ 0x181D, 0x2024, 0x202B, 0x2033, 0x203C, 0x2846, 0x2850, 0x285B, 0x3067,
+ 0x3073, 0x3080, 0x388E, 0x389C, 0x38AB, 0x38BB, 0x40CC, 0x40DD, 0x40EF,
+ 0x4902, 0x4915, 0x4929, 0x513E, 0x5153, 0x5169, 0x5180, 0x5998, 0x59B0,
+ 0x59C9, 0x61E3, 0x61FD, 0x6218, 0x6A34, 0x6A50, 0x6A6D, 0x6A8B, 0x72AA,
+ 0x72C9, 0x72E9, 0x7B0A, 0x7B2B, 0x7B4D, 0x8370, 0x8393, 0x83B7, 0x83DC,
+ 0x8C02, 0x8C28, 0x8C4F, 0x9477, 0x949F, 0x94C8, 0x9CF2, 0x051C, 0x051C,
+ 0x051C, 0x051C,
+};
+
+// wuffs_base__private_implementation__powers_of_5 contains the powers of 5,
+// concatenated together: "5", "25", "125", "625", "3125", etc.
+static const uint8_t wuffs_base__private_implementation__powers_of_5[0x051C] = {
+ 5, 2, 5, 1, 2, 5, 6, 2, 5, 3, 1, 2, 5, 1, 5, 6, 2, 5, 7, 8, 1, 2, 5, 3, 9,
+ 0, 6, 2, 5, 1, 9, 5, 3, 1, 2, 5, 9, 7, 6, 5, 6, 2, 5, 4, 8, 8, 2, 8, 1, 2,
+ 5, 2, 4, 4, 1, 4, 0, 6, 2, 5, 1, 2, 2, 0, 7, 0, 3, 1, 2, 5, 6, 1, 0, 3, 5,
+ 1, 5, 6, 2, 5, 3, 0, 5, 1, 7, 5, 7, 8, 1, 2, 5, 1, 5, 2, 5, 8, 7, 8, 9, 0,
+ 6, 2, 5, 7, 6, 2, 9, 3, 9, 4, 5, 3, 1, 2, 5, 3, 8, 1, 4, 6, 9, 7, 2, 6, 5,
+ 6, 2, 5, 1, 9, 0, 7, 3, 4, 8, 6, 3, 2, 8, 1, 2, 5, 9, 5, 3, 6, 7, 4, 3, 1,
+ 6, 4, 0, 6, 2, 5, 4, 7, 6, 8, 3, 7, 1, 5, 8, 2, 0, 3, 1, 2, 5, 2, 3, 8, 4,
+ 1, 8, 5, 7, 9, 1, 0, 1, 5, 6, 2, 5, 1, 1, 9, 2, 0, 9, 2, 8, 9, 5, 5, 0, 7,
+ 8, 1, 2, 5, 5, 9, 6, 0, 4, 6, 4, 4, 7, 7, 5, 3, 9, 0, 6, 2, 5, 2, 9, 8, 0,
+ 2, 3, 2, 2, 3, 8, 7, 6, 9, 5, 3, 1, 2, 5, 1, 4, 9, 0, 1, 1, 6, 1, 1, 9, 3,
+ 8, 4, 7, 6, 5, 6, 2, 5, 7, 4, 5, 0, 5, 8, 0, 5, 9, 6, 9, 2, 3, 8, 2, 8, 1,
+ 2, 5, 3, 7, 2, 5, 2, 9, 0, 2, 9, 8, 4, 6, 1, 9, 1, 4, 0, 6, 2, 5, 1, 8, 6,
+ 2, 6, 4, 5, 1, 4, 9, 2, 3, 0, 9, 5, 7, 0, 3, 1, 2, 5, 9, 3, 1, 3, 2, 2, 5,
+ 7, 4, 6, 1, 5, 4, 7, 8, 5, 1, 5, 6, 2, 5, 4, 6, 5, 6, 6, 1, 2, 8, 7, 3, 0,
+ 7, 7, 3, 9, 2, 5, 7, 8, 1, 2, 5, 2, 3, 2, 8, 3, 0, 6, 4, 3, 6, 5, 3, 8, 6,
+ 9, 6, 2, 8, 9, 0, 6, 2, 5, 1, 1, 6, 4, 1, 5, 3, 2, 1, 8, 2, 6, 9, 3, 4, 8,
+ 1, 4, 4, 5, 3, 1, 2, 5, 5, 8, 2, 0, 7, 6, 6, 0, 9, 1, 3, 4, 6, 7, 4, 0, 7,
+ 2, 2, 6, 5, 6, 2, 5, 2, 9, 1, 0, 3, 8, 3, 0, 4, 5, 6, 7, 3, 3, 7, 0, 3, 6,
+ 1, 3, 2, 8, 1, 2, 5, 1, 4, 5, 5, 1, 9, 1, 5, 2, 2, 8, 3, 6, 6, 8, 5, 1, 8,
+ 0, 6, 6, 4, 0, 6, 2, 5, 7, 2, 7, 5, 9, 5, 7, 6, 1, 4, 1, 8, 3, 4, 2, 5, 9,
+ 0, 3, 3, 2, 0, 3, 1, 2, 5, 3, 6, 3, 7, 9, 7, 8, 8, 0, 7, 0, 9, 1, 7, 1, 2,
+ 9, 5, 1, 6, 6, 0, 1, 5, 6, 2, 5, 1, 8, 1, 8, 9, 8, 9, 4, 0, 3, 5, 4, 5, 8,
+ 5, 6, 4, 7, 5, 8, 3, 0, 0, 7, 8, 1, 2, 5, 9, 0, 9, 4, 9, 4, 7, 0, 1, 7, 7,
+ 2, 9, 2, 8, 2, 3, 7, 9, 1, 5, 0, 3, 9, 0, 6, 2, 5, 4, 5, 4, 7, 4, 7, 3, 5,
+ 0, 8, 8, 6, 4, 6, 4, 1, 1, 8, 9, 5, 7, 5, 1, 9, 5, 3, 1, 2, 5, 2, 2, 7, 3,
+ 7, 3, 6, 7, 5, 4, 4, 3, 2, 3, 2, 0, 5, 9, 4, 7, 8, 7, 5, 9, 7, 6, 5, 6, 2,
+ 5, 1, 1, 3, 6, 8, 6, 8, 3, 7, 7, 2, 1, 6, 1, 6, 0, 2, 9, 7, 3, 9, 3, 7, 9,
+ 8, 8, 2, 8, 1, 2, 5, 5, 6, 8, 4, 3, 4, 1, 8, 8, 6, 0, 8, 0, 8, 0, 1, 4, 8,
+ 6, 9, 6, 8, 9, 9, 4, 1, 4, 0, 6, 2, 5, 2, 8, 4, 2, 1, 7, 0, 9, 4, 3, 0, 4,
+ 0, 4, 0, 0, 7, 4, 3, 4, 8, 4, 4, 9, 7, 0, 7, 0, 3, 1, 2, 5, 1, 4, 2, 1, 0,
+ 8, 5, 4, 7, 1, 5, 2, 0, 2, 0, 0, 3, 7, 1, 7, 4, 2, 2, 4, 8, 5, 3, 5, 1, 5,
+ 6, 2, 5, 7, 1, 0, 5, 4, 2, 7, 3, 5, 7, 6, 0, 1, 0, 0, 1, 8, 5, 8, 7, 1, 1,
+ 2, 4, 2, 6, 7, 5, 7, 8, 1, 2, 5, 3, 5, 5, 2, 7, 1, 3, 6, 7, 8, 8, 0, 0, 5,
+ 0, 0, 9, 2, 9, 3, 5, 5, 6, 2, 1, 3, 3, 7, 8, 9, 0, 6, 2, 5, 1, 7, 7, 6, 3,
+ 5, 6, 8, 3, 9, 4, 0, 0, 2, 5, 0, 4, 6, 4, 6, 7, 7, 8, 1, 0, 6, 6, 8, 9, 4,
+ 5, 3, 1, 2, 5, 8, 8, 8, 1, 7, 8, 4, 1, 9, 7, 0, 0, 1, 2, 5, 2, 3, 2, 3, 3,
+ 8, 9, 0, 5, 3, 3, 4, 4, 7, 2, 6, 5, 6, 2, 5, 4, 4, 4, 0, 8, 9, 2, 0, 9, 8,
+ 5, 0, 0, 6, 2, 6, 1, 6, 1, 6, 9, 4, 5, 2, 6, 6, 7, 2, 3, 6, 3, 2, 8, 1, 2,
+ 5, 2, 2, 2, 0, 4, 4, 6, 0, 4, 9, 2, 5, 0, 3, 1, 3, 0, 8, 0, 8, 4, 7, 2, 6,
+ 3, 3, 3, 6, 1, 8, 1, 6, 4, 0, 6, 2, 5, 1, 1, 1, 0, 2, 2, 3, 0, 2, 4, 6, 2,
+ 5, 1, 5, 6, 5, 4, 0, 4, 2, 3, 6, 3, 1, 6, 6, 8, 0, 9, 0, 8, 2, 0, 3, 1, 2,
+ 5, 5, 5, 5, 1, 1, 1, 5, 1, 2, 3, 1, 2, 5, 7, 8, 2, 7, 0, 2, 1, 1, 8, 1, 5,
+ 8, 3, 4, 0, 4, 5, 4, 1, 0, 1, 5, 6, 2, 5, 2, 7, 7, 5, 5, 5, 7, 5, 6, 1, 5,
+ 6, 2, 8, 9, 1, 3, 5, 1, 0, 5, 9, 0, 7, 9, 1, 7, 0, 2, 2, 7, 0, 5, 0, 7, 8,
+ 1, 2, 5, 1, 3, 8, 7, 7, 7, 8, 7, 8, 0, 7, 8, 1, 4, 4, 5, 6, 7, 5, 5, 2, 9,
+ 5, 3, 9, 5, 8, 5, 1, 1, 3, 5, 2, 5, 3, 9, 0, 6, 2, 5, 6, 9, 3, 8, 8, 9, 3,
+ 9, 0, 3, 9, 0, 7, 2, 2, 8, 3, 7, 7, 6, 4, 7, 6, 9, 7, 9, 2, 5, 5, 6, 7, 6,
+ 2, 6, 9, 5, 3, 1, 2, 5, 3, 4, 6, 9, 4, 4, 6, 9, 5, 1, 9, 5, 3, 6, 1, 4, 1,
+ 8, 8, 8, 2, 3, 8, 4, 8, 9, 6, 2, 7, 8, 3, 8, 1, 3, 4, 7, 6, 5, 6, 2, 5, 1,
+ 7, 3, 4, 7, 2, 3, 4, 7, 5, 9, 7, 6, 8, 0, 7, 0, 9, 4, 4, 1, 1, 9, 2, 4, 4,
+ 8, 1, 3, 9, 1, 9, 0, 6, 7, 3, 8, 2, 8, 1, 2, 5, 8, 6, 7, 3, 6, 1, 7, 3, 7,
+ 9, 8, 8, 4, 0, 3, 5, 4, 7, 2, 0, 5, 9, 6, 2, 2, 4, 0, 6, 9, 5, 9, 5, 3, 3,
+ 6, 9, 1, 4, 0, 6, 2, 5,
+};
+
+// wuffs_base__private_implementation__high_prec_dec__lshift_num_new_digits
+// returns the number of additional decimal digits when left-shifting by shift.
+//
+// See below for preconditions.
+static uint32_t //
+wuffs_base__private_implementation__high_prec_dec__lshift_num_new_digits(
+ wuffs_base__private_implementation__high_prec_dec* h,
+ uint32_t shift) {
+ // Masking with 0x3F should be unnecessary (assuming the preconditions) but
+ // it's cheap and ensures that we don't overflow the
+ // wuffs_base__private_implementation__hpd_left_shift array.
+ shift &= 63;
+
+ uint32_t x_a = wuffs_base__private_implementation__hpd_left_shift[shift];
+ uint32_t x_b = wuffs_base__private_implementation__hpd_left_shift[shift + 1];
+ uint32_t num_new_digits = x_a >> 11;
+ uint32_t pow5_a = 0x7FF & x_a;
+ uint32_t pow5_b = 0x7FF & x_b;
+
+ const uint8_t* pow5 =
+ &wuffs_base__private_implementation__powers_of_5[pow5_a];
+ uint32_t i = 0;
+ uint32_t n = pow5_b - pow5_a;
+ for (; i < n; i++) {
+ if (i >= h->num_digits) {
+ return num_new_digits - 1;
+ } else if (h->digits[i] == pow5[i]) {
+ continue;
+ } else if (h->digits[i] < pow5[i]) {
+ return num_new_digits - 1;
+ } else {
+ return num_new_digits;
+ }
+ }
+ return num_new_digits;
+}
+
+// --------
+
+// wuffs_base__private_implementation__high_prec_dec__rounded_integer returns
+// the integral (non-fractional) part of h, provided that it is 18 or fewer
+// decimal digits. For 19 or more digits, it returns UINT64_MAX. Note that:
+// - (1 << 53) is 9007199254740992, which has 16 decimal digits.
+// - (1 << 56) is 72057594037927936, which has 17 decimal digits.
+// - (1 << 59) is 576460752303423488, which has 18 decimal digits.
+// - (1 << 63) is 9223372036854775808, which has 19 decimal digits.
+// and that IEEE 754 double precision has 52 mantissa bits.
+//
+// That integral part is rounded-to-even: rounding 7.5 or 8.5 both give 8.
+//
+// h's negative bit is ignored: rounding -8.6 returns 9.
+//
+// See below for preconditions.
+static uint64_t //
+wuffs_base__private_implementation__high_prec_dec__rounded_integer(
+ wuffs_base__private_implementation__high_prec_dec* h) {
+ if ((h->num_digits == 0) || (h->decimal_point < 0)) {
+ return 0;
+ } else if (h->decimal_point > 18) {
+ return UINT64_MAX;
+ }
+
+ uint32_t dp = (uint32_t)(h->decimal_point);
+ uint64_t n = 0;
+ uint32_t i = 0;
+ for (; i < dp; i++) {
+ n = (10 * n) + ((i < h->num_digits) ? h->digits[i] : 0);
+ }
+
+ bool round_up = false;
+ if (dp < h->num_digits) {
+ round_up = h->digits[dp] >= 5;
+ if ((h->digits[dp] == 5) && (dp + 1 == h->num_digits)) {
+ // We are exactly halfway. If we're truncated, round up, otherwise round
+ // to even.
+ round_up = h->truncated || //
+ ((dp > 0) && (1 & h->digits[dp - 1]));
+ }
+ }
+ if (round_up) {
+ n++;
+ }
+
+ return n;
+}
+
+// wuffs_base__private_implementation__high_prec_dec__small_xshift shifts h's
+// number (where 'x' is 'l' or 'r' for left or right) by a small shift value.
+//
+// Preconditions:
+// - h is non-NULL.
+// - h->decimal_point is "not extreme".
+// - shift is non-zero.
+// - shift is "a small shift".
+//
+// "Not extreme" means within
+// ±WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DECIMAL_POINT__RANGE.
+//
+// "A small shift" means not more than
+// WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__SHIFT__MAX_INCL.
+//
+// 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.
+
+static void //
+wuffs_base__private_implementation__high_prec_dec__small_lshift(
+ wuffs_base__private_implementation__high_prec_dec* h,
+ uint32_t shift) {
+ if (h->num_digits == 0) {
+ return;
+ }
+ uint32_t num_new_digits =
+ wuffs_base__private_implementation__high_prec_dec__lshift_num_new_digits(
+ h, shift);
+ uint32_t rx = h->num_digits - 1; // Read index.
+ uint32_t wx = h->num_digits - 1 + num_new_digits; // Write index.
+ uint64_t n = 0;
+
+ // Repeat: pick up a digit, put down a digit, right to left.
+ while (((int32_t)rx) >= 0) {
+ n += ((uint64_t)(h->digits[rx])) << shift;
+ uint64_t quo = n / 10;
+ uint64_t rem = n - (10 * quo);
+ if (wx < WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DIGITS_PRECISION) {
+ h->digits[wx] = (uint8_t)rem;
+ } else if (rem > 0) {
+ h->truncated = true;
+ }
+ n = quo;
+ wx--;
+ rx--;
+ }
+
+ // Put down leading digits, right to left.
+ while (n > 0) {
+ uint64_t quo = n / 10;
+ uint64_t rem = n - (10 * quo);
+ if (wx < WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DIGITS_PRECISION) {
+ h->digits[wx] = (uint8_t)rem;
+ } else if (rem > 0) {
+ h->truncated = true;
+ }
+ n = quo;
+ wx--;
+ }
+
+ // Finish.
+ h->num_digits += num_new_digits;
+ if (h->num_digits >
+ WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DIGITS_PRECISION) {
+ h->num_digits = WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DIGITS_PRECISION;
+ }
+ h->decimal_point += (int32_t)num_new_digits;
+ wuffs_base__private_implementation__high_prec_dec__trim(h);
+}
+
+static void //
+wuffs_base__private_implementation__high_prec_dec__small_rshift(
+ wuffs_base__private_implementation__high_prec_dec* h,
+ uint32_t shift) {
+ uint32_t rx = 0; // Read index.
+ uint32_t wx = 0; // Write index.
+ uint64_t n = 0;
+
+ // Pick up enough leading digits to cover the first shift.
+ while ((n >> shift) == 0) {
+ if (rx < h->num_digits) {
+ // Read a digit.
+ n = (10 * n) + h->digits[rx++];
+ } else if (n == 0) {
+ // h's number used to be zero and remains zero.
+ return;
+ } else {
+ // Read sufficient implicit trailing zeroes.
+ while ((n >> shift) == 0) {
+ n = 10 * n;
+ rx++;
+ }
+ break;
+ }
+ }
+ h->decimal_point -= ((int32_t)(rx - 1));
+ if (h->decimal_point <
+ -WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DECIMAL_POINT__RANGE) {
+ // After the shift, h's number is effectively zero.
+ h->num_digits = 0;
+ h->decimal_point = 0;
+ h->negative = false;
+ h->truncated = false;
+ return;
+ }
+
+ // Repeat: pick up a digit, put down a digit, left to right.
+ uint64_t mask = (((uint64_t)(1)) << shift) - 1;
+ while (rx < h->num_digits) {
+ uint8_t new_digit = ((uint8_t)(n >> shift));
+ n = (10 * (n & mask)) + h->digits[rx++];
+ h->digits[wx++] = new_digit;
+ }
+
+ // Put down trailing digits, left to right.
+ while (n > 0) {
+ uint8_t new_digit = ((uint8_t)(n >> shift));
+ n = 10 * (n & mask);
+ if (wx < WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DIGITS_PRECISION) {
+ h->digits[wx++] = new_digit;
+ } else if (new_digit > 0) {
+ h->truncated = true;
+ }
+ }
+
+ // Finish.
+ h->num_digits = wx;
+ wuffs_base__private_implementation__high_prec_dec__trim(h);
+}
+
+// --------
+
+wuffs_base__result_f64 //
+wuffs_base__parse_number_f64_special(wuffs_base__slice_u8 s,
+ const char* fallback_status_repr) {
+ do {
+ uint8_t* p = s.ptr;
+ uint8_t* q = s.ptr + s.len;
+
+ for (; (p < q) && (*p == '_'); p++) {
+ }
+ if (p >= q) {
+ goto fallback;
+ }
+
+ // Parse sign.
+ bool negative = false;
+ do {
+ if (*p == '+') {
+ p++;
+ } else if (*p == '-') {
+ negative = true;
+ p++;
+ } else {
+ break;
+ }
+ for (; (p < q) && (*p == '_'); p++) {
+ }
+ } while (0);
+ if (p >= q) {
+ goto fallback;
+ }
+
+ bool nan = false;
+ switch (p[0]) {
+ case 'I':
+ case 'i':
+ if (((q - p) < 3) || //
+ ((p[1] != 'N') && (p[1] != 'n')) || //
+ ((p[2] != 'F') && (p[2] != 'f'))) {
+ goto fallback;
+ }
+ p += 3;
+
+ if ((p >= q) || (*p == '_')) {
+ break;
+ } else if (((q - p) < 5) || //
+ ((p[0] != 'I') && (p[0] != 'i')) || //
+ ((p[1] != 'N') && (p[1] != 'n')) || //
+ ((p[2] != 'I') && (p[2] != 'i')) || //
+ ((p[3] != 'T') && (p[3] != 't')) || //
+ ((p[4] != 'Y') && (p[4] != 'y'))) {
+ goto fallback;
+ }
+ p += 5;
+
+ if ((p >= q) || (*p == '_')) {
+ break;
+ }
+ goto fallback;
+
+ case 'N':
+ case 'n':
+ if (((q - p) < 3) || //
+ ((p[1] != 'A') && (p[1] != 'a')) || //
+ ((p[2] != 'N') && (p[2] != 'n'))) {
+ goto fallback;
+ }
+ p += 3;
+
+ if ((p >= q) || (*p == '_')) {
+ nan = true;
+ break;
+ }
+ goto fallback;
+
+ default:
+ goto fallback;
+ }
+
+ // Finish.
+ for (; (p < q) && (*p == '_'); p++) {
+ }
+ if (p != q) {
+ goto fallback;
+ }
+ wuffs_base__result_f64 ret;
+ ret.status.repr = NULL;
+ ret.value = wuffs_base__ieee_754_bit_representation__to_f64(
+ (nan ? 0x7FFFFFFFFFFFFFFF : 0x7FF0000000000000) |
+ (negative ? 0x8000000000000000 : 0));
+ return ret;
+ } while (0);
+
+fallback:
+ do {
+ wuffs_base__result_f64 ret;
+ ret.status.repr = fallback_status_repr;
+ ret.value = 0;
+ return ret;
+ } while (0);
+}
+
+wuffs_base__result_f64 //
+wuffs_base__parse_number_f64(wuffs_base__slice_u8 s) {
+ wuffs_base__private_implementation__high_prec_dec h;
+
+ do {
+ // powers converts decimal powers of 10 to binary powers of 2. For example,
+ // (10000 >> 13) is 1. It stops before the elements exceed 60, also known
+ // as WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__SHIFT__MAX_INCL.
+ static const uint32_t num_powers = 19;
+ static const uint8_t powers[19] = {
+ 0, 3, 6, 9, 13, 16, 19, 23, 26, 29, //
+ 33, 36, 39, 43, 46, 49, 53, 56, 59, //
+ };
+
+ wuffs_base__status status =
+ wuffs_base__private_implementation__high_prec_dec__parse(&h, s);
+ if (status.repr) {
+ return wuffs_base__parse_number_f64_special(s, status.repr);
+ }
+
+ // Handle zero and obvious extremes. The largest and smallest positive
+ // finite f64 values are approximately 1.8e+308 and 4.9e-324.
+ if ((h.num_digits == 0) || (h.decimal_point < -326)) {
+ goto zero;
+ } else if (h.decimal_point > 310) {
+ goto infinity;
+ }
+
+ // Scale by powers of 2 until we're in the range [½ .. 1], which gives us
+ // our exponent (in base-2). First we shift right, possibly a little too
+ // far, ending with a value certainly below 1 and possibly below ½...
+ const int32_t bias = -1023;
+ int32_t exp2 = 0;
+ while (h.decimal_point > 0) {
+ uint32_t n = (uint32_t)(+h.decimal_point);
+ uint32_t shift =
+ (n < num_powers)
+ ? powers[n]
+ : WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__SHIFT__MAX_INCL;
+
+ wuffs_base__private_implementation__high_prec_dec__small_rshift(&h,
+ shift);
+ if (h.decimal_point <
+ -WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DECIMAL_POINT__RANGE) {
+ goto zero;
+ }
+ exp2 += (int32_t)shift;
+ }
+ // ...then we shift left, putting us in [½ .. 1].
+ while (h.decimal_point <= 0) {
+ uint32_t shift;
+ if (h.decimal_point == 0) {
+ if (h.digits[0] >= 5) {
+ break;
+ }
+ shift = (h.digits[0] <= 2) ? 2 : 1;
+ } else {
+ uint32_t n = (uint32_t)(-h.decimal_point);
+ shift = (n < num_powers)
+ ? powers[n]
+ : WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__SHIFT__MAX_INCL;
+ }
+
+ wuffs_base__private_implementation__high_prec_dec__small_lshift(&h,
+ shift);
+ if (h.decimal_point >
+ +WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DECIMAL_POINT__RANGE) {
+ goto infinity;
+ }
+ exp2 -= (int32_t)shift;
+ }
+
+ // We're in the range [½ .. 1] but f64 uses [1 .. 2].
+ exp2--;
+
+ // The minimum normal exponent is (bias + 1).
+ while ((bias + 1) > exp2) {
+ uint32_t n = (uint32_t)((bias + 1) - exp2);
+ if (n > WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__SHIFT__MAX_INCL) {
+ n = WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__SHIFT__MAX_INCL;
+ }
+ wuffs_base__private_implementation__high_prec_dec__small_rshift(&h, n);
+ exp2 += (int32_t)n;
+ }
+
+ // Check for overflow.
+ if ((exp2 - bias) >= 0x07FF) { // (1 << 11) - 1.
+ goto infinity;
+ }
+
+ // Extract 53 bits for the mantissa (in base-2).
+ wuffs_base__private_implementation__high_prec_dec__small_lshift(&h, 53);
+ uint64_t man2 =
+ wuffs_base__private_implementation__high_prec_dec__rounded_integer(&h);
+
+ // Rounding might have added one bit. If so, shift and re-check overflow.
+ if ((man2 >> 53) != 0) {
+ man2 >>= 1;
+ exp2++;
+ if ((exp2 - bias) >= 0x07FF) { // (1 << 11) - 1.
+ goto infinity;
+ }
+ }
+
+ // Handle subnormal numbers.
+ if ((man2 >> 52) == 0) {
+ exp2 = bias;
+ }
+
+ // Pack the bits and return.
+ uint64_t exp2_bits = (uint64_t)((exp2 - bias) & 0x07FF); // (1 << 11) - 1.
+ uint64_t bits = (man2 & 0x000FFFFFFFFFFFFF) | // (1 << 52) - 1.
+ (exp2_bits << 52) | //
+ (h.negative ? 0x8000000000000000 : 0); // (1 << 63).
+
+ wuffs_base__result_f64 ret;
+ ret.status.repr = NULL;
+ ret.value = wuffs_base__ieee_754_bit_representation__to_f64(bits);
+ return ret;
+ } while (0);
+
+zero:
+ do {
+ uint64_t bits = h.negative ? 0x8000000000000000 : 0;
+
+ wuffs_base__result_f64 ret;
+ ret.status.repr = NULL;
+ ret.value = wuffs_base__ieee_754_bit_representation__to_f64(bits);
+ return ret;
+ } while (0);
+
+infinity:
+ do {
+ uint64_t bits = h.negative ? 0xFFF0000000000000 : 0x7FF0000000000000;
+
+ wuffs_base__result_f64 ret;
+ ret.status.repr = NULL;
+ ret.value = wuffs_base__ieee_754_bit_representation__to_f64(bits);
+ return ret;
+ } while (0);
+}
+
// ---------------- Unicode and UTF-8
size_t //
diff --git a/internal/cgen/base/strconv-public.h b/internal/cgen/base/strconv-public.h
index ce47874..65c60ec 100644
--- a/internal/cgen/base/strconv-public.h
+++ b/internal/cgen/base/strconv-public.h
@@ -54,7 +54,73 @@
wuffs_base__result_u64 //
wuffs_base__parse_number_u64(wuffs_base__slice_u8 s);
-// ---------------- Unicode and UTF-8
+// ---------------- IEEE 754 Floating Point
+
+// wuffs_base__parse_number_f64 parses the floating point number in s. For
+// example, if s contains the bytes "1.5" then it will return the double 1.5.
+//
+// It returns an error if s does not contain a floating point number.
+//
+// It does not necessarily return an error if the conversion is lossy, e.g. if
+// s is "0.3", which double-precision floating point cannot represent exactly.
+//
+// Similarly, the returned value may be infinite (and no error returned) even
+// if s was not "inf", when the input is nominally finite but sufficiently
+// larger than DBL_MAX, about 1.8e+308.
+//
+// It is similar to the C standard library's strtod function, but:
+// - Errors are returned in-band (in a result type), not out-of-band (errno).
+// - It takes a slice (a pointer and length), not a NUL-terminated C string.
+// - It does not take an optional endptr argument. It does not allow a partial
+// parse: it returns an error unless all of s is consumed.
+// - It does not allow whitespace, leading or otherwise.
+// - It does not allow unnecessary leading zeroes ("0" is valid and its sole
+// zero is necessary). All of "00", "0644" and "00.7" are invalid.
+// - It is not affected by i18n / l10n settings such as environment variables.
+// - Conversely, it always accepts either ',' or '.' as a decimal separator.
+// In particular, "3,141,592" is always invalid but "3,141" is always valid
+// (and approximately π). The caller is responsible for e.g. previously
+// rejecting or filtering s if it contains a comma, if that is unacceptable
+// to the caller. For example, JSON numbers always use a dot '.' and never a
+// comma ',', regardless of the LOCALE environment variable.
+// - It does allow arbitrary underscores. For example, "_3.141_592" would
+// successfully parse, again approximately π.
+// - It does allow "inf", "+Infinity" and "-NAN", case insensitive, but it
+// does not permit "nan" to be followed by an integer mantissa.
+// - It does not allow hexadecimal floating point numbers.
+wuffs_base__result_f64 //
+wuffs_base__parse_number_f64(wuffs_base__slice_u8 s);
+
+// wuffs_base__ieee_754_bit_representation__etc converts between a double
+// precision numerical value and its IEEE 754 64-bit representation (1 sign
+// bit, 11 exponent bits, 52 explicit significand bits).
+//
+// For example, it converts between:
+// - +1.0 and 0x3FF0_0000_0000_0000.
+// - +5.5 and 0x4016_0000_0000_0000.
+// - -inf and 0xFFF0_0000_0000_0000.
+//
+// See https://en.wikipedia.org/wiki/Double-precision_floating-point_format
+
+static inline uint64_t //
+wuffs_base__ieee_754_bit_representation__from_f64(double f) {
+ uint64_t u = 0;
+ if (sizeof(uint64_t) == sizeof(double)) {
+ memcpy(&u, &f, sizeof(uint64_t));
+ }
+ return u;
+}
+
+static inline double //
+wuffs_base__ieee_754_bit_representation__to_f64(uint64_t u) {
+ double f = 0;
+ if (sizeof(uint64_t) == sizeof(double)) {
+ memcpy(&f, &u, sizeof(uint64_t));
+ }
+ return f;
+}
+
+ // ---------------- Unicode and UTF-8
#define WUFFS_BASE__UNICODE_CODE_POINT__MIN_INCL 0x00000000
#define WUFFS_BASE__UNICODE_CODE_POINT__MAX_INCL 0x0010FFFF
@@ -140,7 +206,7 @@
//
// s will never be too short if its length is at least 4, also known as
// WUFFS_BASE__UTF_8__BYTE_LENGTH__MAX_INCL.
-size_t //
+size_t //
wuffs_base__utf_8__encode(wuffs_base__slice_u8 dst, uint32_t code_point);
// wuffs_base__utf_8__next returns the next UTF-8 code point (and that code
diff --git a/internal/cgen/data.go b/internal/cgen/data.go
index cf6f0fa..505e252 100644
--- a/internal/cgen/data.go
+++ b/internal/cgen/data.go
@@ -77,7 +77,42 @@
"alue = +(int64_t)(r.value);\n return ret;\n }\n } while (0);\n\nfail_bad_argument:\n do {\n wuffs_base__result_i64 ret;\n ret.status.repr = wuffs_base__error__bad_argument;\n ret.value = 0;\n return ret;\n } while (0);\n\nfail_out_of_bounds:\n do {\n wuffs_base__result_i64 ret;\n ret.status.repr = wuffs_base__error__out_of_bounds;\n ret.value = 0;\n return ret;\n } while (0);\n}\n\nwuffs_base__result_u64 //\nwuffs_base__parse_number_u64(wuffs_base__slice_u8 s) {\n uint8_t* p = s.ptr;\n uint8_t* q = s.ptr + s.len;\n\n for (; (p < q) && (*p == '_'); p++) {\n }\n\n if (p >= q) {\n goto fail_bad_argument;\n\n } else if (*p == '0') {\n p++;\n if (p >= q) {\n goto ok_zero;\n }\n if (*p == '_') {\n p++;\n for (; p < q; p++) {\n if (*p != '_') {\n goto fail_bad_argument;\n }\n }\n goto ok_zero;\n }\n\n if ((*p == 'x') || (*p == 'X')) {\n p++;\n for (; (p < q) && (*p == '_'); p++) {\n }\n if (p < q) {\n goto hexadecimal;\n }\n\n " +
" } else if ((*p == 'd') || (*p == 'D')) {\n p++;\n for (; (p < q) && (*p == '_'); p++) {\n }\n if (p < q) {\n goto decimal;\n }\n }\n\n goto fail_bad_argument;\n }\n\ndecimal:\n do {\n uint64_t v = wuffs_base__parse_number__decimal_digits[*p++];\n if (v == 0) {\n goto fail_bad_argument;\n }\n v &= 0x0F;\n\n // UINT64_MAX is 18446744073709551615, which is ((10 * max10) + max1).\n const uint64_t max10 = 1844674407370955161;\n const uint8_t max1 = 5;\n\n for (; p < q; p++) {\n if (*p == '_') {\n continue;\n }\n uint8_t digit = wuffs_base__parse_number__decimal_digits[*p];\n if (digit == 0) {\n goto fail_bad_argument;\n }\n digit &= 0x0F;\n if ((v > max10) || ((v == max10) && (digit > max1))) {\n goto fail_out_of_bounds;\n }\n v = (10 * v) + ((uint64_t)(digit));\n }\n\n wuffs_base__result_u64 ret;\n ret.status.repr = NULL;\n ret.value = v;\n return ret;\n } while (0);\n\nhexadecimal:\n do {\n uint64_t v = " +
"wuffs_base__parse_number__hexadecimal_digits[*p++];\n if (v == 0) {\n goto fail_bad_argument;\n }\n v &= 0x0F;\n\n for (; p < q; p++) {\n if (*p == '_') {\n continue;\n }\n uint8_t digit = wuffs_base__parse_number__hexadecimal_digits[*p];\n if (digit == 0) {\n goto fail_bad_argument;\n }\n digit &= 0x0F;\n if ((v >> 60) != 0) {\n goto fail_out_of_bounds;\n }\n v = (v << 4) | ((uint64_t)(digit));\n }\n\n wuffs_base__result_u64 ret;\n ret.status.repr = NULL;\n ret.value = v;\n return ret;\n } while (0);\n\nok_zero:\n do {\n wuffs_base__result_u64 ret;\n ret.status.repr = NULL;\n ret.value = 0;\n return ret;\n } while (0);\n\nfail_bad_argument:\n do {\n wuffs_base__result_u64 ret;\n ret.status.repr = wuffs_base__error__bad_argument;\n ret.value = 0;\n return ret;\n } while (0);\n\nfail_out_of_bounds:\n do {\n wuffs_base__result_u64 ret;\n ret.status.repr = wuffs_base__error__out_of_bounds;\n ret.value = 0;\n return ret;\n " +
- " } while (0);\n}\n\n" +
+ " } while (0);\n}\n\n " +
+ "" +
+ "// ---------------- 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// 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. The ±1023\n// bounds are further away from zero than ±(324 + 500), where 500 and 1023 is\n// WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DIGITS_PRE" +
+ "CISION 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 HP" +
+ "D 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_P" +
+ "OINT__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 +WU" +
+ "FFS_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//" +
+ " etc__powers_of_5 array (of length 0x051C, so offsets fit in 11 bits). When i\n// is 4, its offset and the next one is 6 and 9, and etc__powers_of_5[6 .. 9]\n// is the string \"\\x06\\x02\\x05\", so the relevant power of 5 is \"625\".\n//\n// Thanks to Ken Thompson for the original idea.\nstatic const uint16_t wuffs_base__private_implementation__hpd_left_shift[65] = {\n 0x0000, 0x0800, 0x0801, 0x0803, 0x1006, 0x1009, 0x100D, 0x1812, 0x1817,\n 0x181D, 0x2024, 0x202B, 0x2033, 0x203C, 0x2846, 0x2850, 0x285B, 0x3067,\n 0x3073, 0x3080, 0x388E, 0x389C, 0x38AB, 0x38BB, 0x40CC, 0x40DD, 0x40EF,\n 0x4902, 0x4915, 0x4929, 0x513E, 0x5153, 0x5169, 0x5180, 0x5998, 0x59B0,\n 0x59C9, 0x61E3, 0x61FD, 0x6218, 0x6A34, 0x6A50, 0x6A6D, 0x6A8B, 0x72AA,\n 0x72C9, 0x72E9, 0x7B0A, 0x7B2B, 0x7B4D, 0x8370, 0x8393, 0x83B7, 0x83DC,\n 0x8C02, 0x8C28, 0x8C4F, 0x9477, 0x949F, 0x94C8, 0x9CF2, 0x051C, 0x051C,\n 0x051C, 0x051C,\n};\n\n// wuffs_base__private_implementation__powers_of_5 contains the powers of 5,\n// concatenated together: \"5\", \"" +
+ "25\", \"125\", \"625\", \"3125\", etc.\nstatic const uint8_t wuffs_base__private_implementation__powers_of_5[0x051C] = {\n 5, 2, 5, 1, 2, 5, 6, 2, 5, 3, 1, 2, 5, 1, 5, 6, 2, 5, 7, 8, 1, 2, 5, 3, 9,\n 0, 6, 2, 5, 1, 9, 5, 3, 1, 2, 5, 9, 7, 6, 5, 6, 2, 5, 4, 8, 8, 2, 8, 1, 2,\n 5, 2, 4, 4, 1, 4, 0, 6, 2, 5, 1, 2, 2, 0, 7, 0, 3, 1, 2, 5, 6, 1, 0, 3, 5,\n 1, 5, 6, 2, 5, 3, 0, 5, 1, 7, 5, 7, 8, 1, 2, 5, 1, 5, 2, 5, 8, 7, 8, 9, 0,\n 6, 2, 5, 7, 6, 2, 9, 3, 9, 4, 5, 3, 1, 2, 5, 3, 8, 1, 4, 6, 9, 7, 2, 6, 5,\n 6, 2, 5, 1, 9, 0, 7, 3, 4, 8, 6, 3, 2, 8, 1, 2, 5, 9, 5, 3, 6, 7, 4, 3, 1,\n 6, 4, 0, 6, 2, 5, 4, 7, 6, 8, 3, 7, 1, 5, 8, 2, 0, 3, 1, 2, 5, 2, 3, 8, 4,\n 1, 8, 5, 7, 9, 1, 0, 1, 5, 6, 2, 5, 1, 1, 9, 2, 0, 9, 2, 8, 9, 5, 5, 0, 7,\n 8, 1, 2, 5, 5, 9, 6, 0, 4, 6, 4, 4, 7, 7, 5, 3, 9, 0, 6, 2, 5, 2, 9, 8, 0,\n 2, 3, 2, 2, 3, 8, 7, 6, 9, 5, 3, 1, 2, 5, 1, 4, 9, 0, 1, 1, 6, 1, 1, 9, 3,\n 8, 4, 7, 6, 5, 6, 2, 5, 7, 4, 5, 0, 5, 8, 0, 5, 9, 6, 9, 2, 3, 8, 2, 8, 1,\n 2, 5, 3, 7, 2, 5, 2, 9, 0, 2, 9, 8, 4," +
+ " 6, 1, 9, 1, 4, 0, 6, 2, 5, 1, 8, 6,\n 2, 6, 4, 5, 1, 4, 9, 2, 3, 0, 9, 5, 7, 0, 3, 1, 2, 5, 9, 3, 1, 3, 2, 2, 5,\n 7, 4, 6, 1, 5, 4, 7, 8, 5, 1, 5, 6, 2, 5, 4, 6, 5, 6, 6, 1, 2, 8, 7, 3, 0,\n 7, 7, 3, 9, 2, 5, 7, 8, 1, 2, 5, 2, 3, 2, 8, 3, 0, 6, 4, 3, 6, 5, 3, 8, 6,\n 9, 6, 2, 8, 9, 0, 6, 2, 5, 1, 1, 6, 4, 1, 5, 3, 2, 1, 8, 2, 6, 9, 3, 4, 8,\n 1, 4, 4, 5, 3, 1, 2, 5, 5, 8, 2, 0, 7, 6, 6, 0, 9, 1, 3, 4, 6, 7, 4, 0, 7,\n 2, 2, 6, 5, 6, 2, 5, 2, 9, 1, 0, 3, 8, 3, 0, 4, 5, 6, 7, 3, 3, 7, 0, 3, 6,\n 1, 3, 2, 8, 1, 2, 5, 1, 4, 5, 5, 1, 9, 1, 5, 2, 2, 8, 3, 6, 6, 8, 5, 1, 8,\n 0, 6, 6, 4, 0, 6, 2, 5, 7, 2, 7, 5, 9, 5, 7, 6, 1, 4, 1, 8, 3, 4, 2, 5, 9,\n 0, 3, 3, 2, 0, 3, 1, 2, 5, 3, 6, 3, 7, 9, 7, 8, 8, 0, 7, 0, 9, 1, 7, 1, 2,\n 9, 5, 1, 6, 6, 0, 1, 5, 6, 2, 5, 1, 8, 1, 8, 9, 8, 9, 4, 0, 3, 5, 4, 5, 8,\n 5, 6, 4, 7, 5, 8, 3, 0, 0, 7, 8, 1, 2, 5, 9, 0, 9, 4, 9, 4, 7, 0, 1, 7, 7,\n 2, 9, 2, 8, 2, 3, 7, 9, 1, 5, 0, 3, 9, 0, 6, 2, 5, 4, 5, 4, 7, 4, 7, 3, 5,\n 0, 8, 8, 6, 4, 6, 4, 1, 1, 8, 9, 5," +
+ " 7, 5, 1, 9, 5, 3, 1, 2, 5, 2, 2, 7, 3,\n 7, 3, 6, 7, 5, 4, 4, 3, 2, 3, 2, 0, 5, 9, 4, 7, 8, 7, 5, 9, 7, 6, 5, 6, 2,\n 5, 1, 1, 3, 6, 8, 6, 8, 3, 7, 7, 2, 1, 6, 1, 6, 0, 2, 9, 7, 3, 9, 3, 7, 9,\n 8, 8, 2, 8, 1, 2, 5, 5, 6, 8, 4, 3, 4, 1, 8, 8, 6, 0, 8, 0, 8, 0, 1, 4, 8,\n 6, 9, 6, 8, 9, 9, 4, 1, 4, 0, 6, 2, 5, 2, 8, 4, 2, 1, 7, 0, 9, 4, 3, 0, 4,\n 0, 4, 0, 0, 7, 4, 3, 4, 8, 4, 4, 9, 7, 0, 7, 0, 3, 1, 2, 5, 1, 4, 2, 1, 0,\n 8, 5, 4, 7, 1, 5, 2, 0, 2, 0, 0, 3, 7, 1, 7, 4, 2, 2, 4, 8, 5, 3, 5, 1, 5,\n 6, 2, 5, 7, 1, 0, 5, 4, 2, 7, 3, 5, 7, 6, 0, 1, 0, 0, 1, 8, 5, 8, 7, 1, 1,\n 2, 4, 2, 6, 7, 5, 7, 8, 1, 2, 5, 3, 5, 5, 2, 7, 1, 3, 6, 7, 8, 8, 0, 0, 5,\n 0, 0, 9, 2, 9, 3, 5, 5, 6, 2, 1, 3, 3, 7, 8, 9, 0, 6, 2, 5, 1, 7, 7, 6, 3,\n 5, 6, 8, 3, 9, 4, 0, 0, 2, 5, 0, 4, 6, 4, 6, 7, 7, 8, 1, 0, 6, 6, 8, 9, 4,\n 5, 3, 1, 2, 5, 8, 8, 8, 1, 7, 8, 4, 1, 9, 7, 0, 0, 1, 2, 5, 2, 3, 2, 3, 3,\n 8, 9, 0, 5, 3, 3, 4, 4, 7, 2, 6, 5, 6, 2, 5, 4, 4, 4, 0, 8, 9, 2, 0, 9, 8,\n 5, 0, 0, 6, 2, 6, 1, 6, 1, 6, 9," +
+ " 4, 5, 2, 6, 6, 7, 2, 3, 6, 3, 2, 8, 1, 2,\n 5, 2, 2, 2, 0, 4, 4, 6, 0, 4, 9, 2, 5, 0, 3, 1, 3, 0, 8, 0, 8, 4, 7, 2, 6,\n 3, 3, 3, 6, 1, 8, 1, 6, 4, 0, 6, 2, 5, 1, 1, 1, 0, 2, 2, 3, 0, 2, 4, 6, 2,\n 5, 1, 5, 6, 5, 4, 0, 4, 2, 3, 6, 3, 1, 6, 6, 8, 0, 9, 0, 8, 2, 0, 3, 1, 2,\n 5, 5, 5, 5, 1, 1, 1, 5, 1, 2, 3, 1, 2, 5, 7, 8, 2, 7, 0, 2, 1, 1, 8, 1, 5,\n 8, 3, 4, 0, 4, 5, 4, 1, 0, 1, 5, 6, 2, 5, 2, 7, 7, 5, 5, 5, 7, 5, 6, 1, 5,\n 6, 2, 8, 9, 1, 3, 5, 1, 0, 5, 9, 0, 7, 9, 1, 7, 0, 2, 2, 7, 0, 5, 0, 7, 8,\n 1, 2, 5, 1, 3, 8, 7, 7, 7, 8, 7, 8, 0, 7, 8, 1, 4, 4, 5, 6, 7, 5, 5, 2, 9,\n 5, 3, 9, 5, 8, 5, 1, 1, 3, 5, 2, 5, 3, 9, 0, 6, 2, 5, 6, 9, 3, 8, 8, 9, 3,\n 9, 0, 3, 9, 0, 7, 2, 2, 8, 3, 7, 7, 6, 4, 7, 6, 9, 7, 9, 2, 5, 5, 6, 7, 6,\n 2, 6, 9, 5, 3, 1, 2, 5, 3, 4, 6, 9, 4, 4, 6, 9, 5, 1, 9, 5, 3, 6, 1, 4, 1,\n 8, 8, 8, 2, 3, 8, 4, 8, 9, 6, 2, 7, 8, 3, 8, 1, 3, 4, 7, 6, 5, 6, 2, 5, 1,\n 7, 3, 4, 7, 2, 3, 4, 7, 5, 9, 7, 6, 8, 0, 7, 0, 9, 4, 4, 1, 1, 9, 2, 4, 4,\n 8, 1, 3, 9, 1, 9, 0, 6, 7, 3," +
+ " 8, 2, 8, 1, 2, 5, 8, 6, 7, 3, 6, 1, 7, 3, 7,\n 9, 8, 8, 4, 0, 3, 5, 4, 7, 2, 0, 5, 9, 6, 2, 2, 4, 0, 6, 9, 5, 9, 5, 3, 3,\n 6, 9, 1, 4, 0, 6, 2, 5,\n};\n\n// wuffs_base__private_implementation__high_prec_dec__lshift_num_new_digits\n// returns the number of additional decimal digits when left-shifting by shift.\n//\n// See below for preconditions.\nstatic uint32_t //\nwuffs_base__private_implementation__high_prec_dec__lshift_num_new_digits(\n wuffs_base__private_implementation__high_prec_dec* h,\n uint32_t shift) {\n // Masking with 0x3F should be unnecessary (assuming the preconditions) but\n // it's cheap and ensures that we don't overflow the\n // wuffs_base__private_implementation__hpd_left_shift array.\n shift &= 63;\n\n uint32_t x_a = wuffs_base__private_implementation__hpd_left_shift[shift];\n uint32_t x_b = wuffs_base__private_implementation__hpd_left_shift[shift + 1];\n uint32_t num_new_digits = x_a >> 11;\n uint32_t pow5_a = 0x7FF & x_a;\n uint32_t pow5_b = 0x7FF & x_b;\n\n const uint8_t* pow5 =\n " +
+ " &wuffs_base__private_implementation__powers_of_5[pow5_a];\n uint32_t i = 0;\n uint32_t n = pow5_b - pow5_a;\n for (; i < n; i++) {\n if (i >= h->num_digits) {\n return num_new_digits - 1;\n } else if (h->digits[i] == pow5[i]) {\n continue;\n } else if (h->digits[i] < pow5[i]) {\n return num_new_digits - 1;\n } else {\n return num_new_digits;\n }\n }\n return num_new_digits;\n}\n\n" +
+ "" +
+ "// --------\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" +
+ "" +
+ "// --------\n\nwuffs_base__result_f64 //\nwuffs_base__parse_number_f64_special(wuffs_base__slice_u8 s,\n const char* fallback_status_repr) {\n do {\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 goto fallback;\n }\n\n // Parse sign.\n bool negative = false;\n do {\n if (*p == '+') {\n p++;\n } else if (*p == '-') {\n negative = true;\n p++;\n } else {\n break;\n }\n for (; (p < q) && (*p == '_'); p++) {\n }\n } while (0);\n if (p >= q) {\n goto fallback;\n }\n\n bool nan = false;\n switch (p[0]) {\n case 'I':\n case 'i':\n if (((q - p) < 3) || //\n ((p[1] != 'N') && (p[1] != 'n')) || //\n ((p[2] != 'F') && (p[2] != 'f'))) {\n goto fallback;\n }\n p += 3;\n\n if ((p >= q) || (*p == '_')) {\n break;\n } else if (((q - p) < 5) || " +
+ " //\n ((p[0] != 'I') && (p[0] != 'i')) || //\n ((p[1] != 'N') && (p[1] != 'n')) || //\n ((p[2] != 'I') && (p[2] != 'i')) || //\n ((p[3] != 'T') && (p[3] != 't')) || //\n ((p[4] != 'Y') && (p[4] != 'y'))) {\n goto fallback;\n }\n p += 5;\n\n if ((p >= q) || (*p == '_')) {\n break;\n }\n goto fallback;\n\n case 'N':\n case 'n':\n if (((q - p) < 3) || //\n ((p[1] != 'A') && (p[1] != 'a')) || //\n ((p[2] != 'N') && (p[2] != 'n'))) {\n goto fallback;\n }\n p += 3;\n\n if ((p >= q) || (*p == '_')) {\n nan = true;\n break;\n }\n goto fallback;\n\n default:\n goto fallback;\n }\n\n // Finish.\n for (; (p < q) && (*p == '_'); p++) {\n }\n if (p != q) {\n goto fallback;\n }\n wuffs_base__result_f64 ret;\n ret.status.repr = NULL;\n ret.value = w" +
+ "uffs_base__ieee_754_bit_representation__to_f64(\n (nan ? 0x7FFFFFFFFFFFFFFF : 0x7FF0000000000000) |\n (negative ? 0x8000000000000000 : 0));\n return ret;\n } while (0);\n\nfallback:\n do {\n wuffs_base__result_f64 ret;\n ret.status.repr = fallback_status_repr;\n ret.value = 0;\n return ret;\n } while (0);\n}\n\nwuffs_base__result_f64 //\nwuffs_base__parse_number_f64(wuffs_base__slice_u8 s) {\n wuffs_base__private_implementation__high_prec_dec h;\n\n do {\n // powers converts decimal powers of 10 to binary powers of 2. For example,\n // (10000 >> 13) is 1. It stops before the elements exceed 60, also known\n // as WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__SHIFT__MAX_INCL.\n static const uint32_t num_powers = 19;\n static const uint8_t powers[19] = {\n 0, 3, 6, 9, 13, 16, 19, 23, 26, 29, //\n 33, 36, 39, 43, 46, 49, 53, 56, 59, //\n };\n\n wuffs_base__status status =\n wuffs_base__private_implementation__high_prec_dec__parse(&h, s);\n if (status.repr) {\n" +
+ " return wuffs_base__parse_number_f64_special(s, status.repr);\n }\n\n // Handle zero and obvious extremes. The largest and smallest positive\n // finite f64 values are approximately 1.8e+308 and 4.9e-324.\n if ((h.num_digits == 0) || (h.decimal_point < -326)) {\n goto zero;\n } else if (h.decimal_point > 310) {\n goto infinity;\n }\n\n // Scale by powers of 2 until we're in the range [½ .. 1], which gives us\n // our exponent (in base-2). First we shift right, possibly a little too\n // far, ending with a value certainly below 1 and possibly below ½...\n const int32_t bias = -1023;\n int32_t exp2 = 0;\n while (h.decimal_point > 0) {\n uint32_t n = (uint32_t)(+h.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 sh" +
+ "ift);\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_lshift(&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 (bias + 1).\n while ((bias + 1) > exp2) {\n uint32_t n = (uint32_t)((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 - 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__private_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 - bias) >= 0x07FF) { // (1 << 11) - 1.\n goto infinity;\n }\n }\n\n // Handle subnormal numbers.\n if ((" +
+ "man2 >> 52) == 0) {\n exp2 = bias;\n }\n\n // Pack the bits and return.\n uint64_t exp2_bits = (uint64_t)((exp2 - 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 } whi" +
+ "le (0);\n}\n\n" +
"" +
"// ---------------- Unicode and UTF-8\n\nsize_t //\nwuffs_base__utf_8__encode(wuffs_base__slice_u8 dst, uint32_t code_point) {\n if (code_point <= 0x7F) {\n if (dst.len >= 1) {\n dst.ptr[0] = (uint8_t)(code_point);\n return 1;\n }\n\n } else if (code_point <= 0x07FF) {\n if (dst.len >= 2) {\n dst.ptr[0] = (uint8_t)(0xC0 | ((code_point >> 6)));\n dst.ptr[1] = (uint8_t)(0x80 | ((code_point >> 0) & 0x3F));\n return 2;\n }\n\n } else if (code_point <= 0xFFFF) {\n if ((dst.len >= 3) && ((code_point < 0xD800) || (0xDFFF < code_point))) {\n dst.ptr[0] = (uint8_t)(0xE0 | ((code_point >> 12)));\n dst.ptr[1] = (uint8_t)(0x80 | ((code_point >> 6) & 0x3F));\n dst.ptr[2] = (uint8_t)(0x80 | ((code_point >> 0) & 0x3F));\n return 3;\n }\n\n } else if (code_point <= 0x10FFFF) {\n if (dst.len >= 4) {\n dst.ptr[0] = (uint8_t)(0xF0 | ((code_point >> 18)));\n dst.ptr[1] = (uint8_t)(0x80 | ((code_point >> 12) & 0x3F));\n dst.ptr[2] = (uint8_t)(0x80 | ((code_point >> 6) & 0x3" +
"F));\n dst.ptr[3] = (uint8_t)(0x80 | ((code_point >> 0) & 0x3F));\n return 4;\n }\n }\n\n return 0;\n}\n\n// wuffs_base__utf_8__byte_length_minus_1 is the byte length (minus 1) of a\n// UTF-8 encoded code point, based on the encoding's initial byte.\n// - 0x00 is 1-byte UTF-8 (ASCII).\n// - 0x01 is the start of 2-byte UTF-8.\n// - 0x02 is the start of 3-byte UTF-8.\n// - 0x03 is the start of 4-byte UTF-8.\n// - 0x40 is a UTF-8 tail byte.\n// - 0x80 is invalid UTF-8.\n//\n// RFC 3629 (UTF-8) gives this grammar for valid UTF-8:\n// UTF8-1 = %x00-7F\n// UTF8-2 = %xC2-DF UTF8-tail\n// UTF8-3 = %xE0 %xA0-BF UTF8-tail / %xE1-EC 2( UTF8-tail ) /\n// %xED %x80-9F UTF8-tail / %xEE-EF 2( UTF8-tail )\n// UTF8-4 = %xF0 %x90-BF 2( UTF8-tail ) / %xF1-F3 3( UTF8-tail ) /\n// %xF4 %x80-8F 2( UTF8-tail )\n// UTF8-tail = %x80-BF\nstatic const uint8_t wuffs_base__utf_8__byte_length_minus_1[256] = {\n // 0 1 2 3 4 5 6 7\n // 8 9" +
@@ -119,7 +154,7 @@
"ffs_base__status__is_ok(const wuffs_base__status* z) {\n return z->repr == NULL;\n}\n\nstatic inline bool //\nwuffs_base__status__is_suspension(const wuffs_base__status* z) {\n return z->repr && (*z->repr == '$');\n}\n\n// wuffs_base__status__message strips the leading '$', '#' or '@'.\nstatic inline const char* //\nwuffs_base__status__message(const wuffs_base__status* z) {\n if (z->repr) {\n if ((*z->repr == '$') || (*z->repr == '#') || (*z->repr == '@')) {\n return z->repr + 1;\n }\n }\n return z->repr;\n}\n\n#ifdef __cplusplus\n\ninline bool //\nwuffs_base__status::is_complete() const {\n return wuffs_base__status__is_complete(this);\n}\n\ninline bool //\nwuffs_base__status::is_error() const {\n return wuffs_base__status__is_error(this);\n}\n\ninline bool //\nwuffs_base__status::is_note() const {\n return wuffs_base__status__is_note(this);\n}\n\ninline bool //\nwuffs_base__status::is_ok() const {\n return wuffs_base__status__is_ok(this);\n}\n\ninline bool //\nwuffs_base__status::is_suspension() const {\n return wuffs_base" +
"__status__is_suspension(this);\n}\n\ninline const char* //\nwuffs_base__status::message() const {\n return wuffs_base__status__message(this);\n}\n\n#endif // __cplusplus\n\n" +
"" +
- "// --------\n\n// WUFFS_BASE__RESULT is a result type: either a status (an error) or a value.\n//\n// A result with all fields NULL or zero is as valid as a zero-valued T.\n#define WUFFS_BASE__RESULT(T) \\\n struct { \\\n wuffs_base__status status; \\\n T value; \\\n }\n\ntypedef WUFFS_BASE__RESULT(int64_t) wuffs_base__result_i64;\ntypedef WUFFS_BASE__RESULT(uint64_t) wuffs_base__result_u64;\n\n" +
+ "// --------\n\n// WUFFS_BASE__RESULT is a result type: either a status (an error) or a value.\n//\n// A result with all fields NULL or zero is as valid as a zero-valued T.\n#define WUFFS_BASE__RESULT(T) \\\n struct { \\\n wuffs_base__status status; \\\n T value; \\\n }\n\ntypedef WUFFS_BASE__RESULT(double) wuffs_base__result_f64;\ntypedef WUFFS_BASE__RESULT(int64_t) wuffs_base__result_i64;\ntypedef WUFFS_BASE__RESULT(uint64_t) wuffs_base__result_u64;\n\n" +
"" +
"// --------\n\n// FourCC constants.\n\n// !! INSERT FourCCs.\n\n" +
"" +
@@ -291,15 +326,19 @@
"// - 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__result_u64 //\nwuffs_base__parse_number_u64(wuffs_base__slice_u8 s);\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" +
+ "ing point numbers.\nwuffs_base__result_f64 //\nwuffs_base__parse_number_f64(wuffs_base__slice_u8 s);\n\n// wuffs_base__ieee_754_bit_representation__etc converts between a double\n// precision numerical value and its IEEE 754 64-bit representation (1 sign\n// bit, 11 exponent bits, 52 explicit significand bits).\n//\n// For example, it converts between:\n// - +1.0 and 0x3FF0_0000_0000_0000.\n// - +5.5 and 0x4016_0000_0000_0000.\n// - -inf and 0xFFF0_0000_0000_0000.\n//\n// See https://en.wikipedia.org/wiki/Double-precision_floating-point_format\n\nstatic inline uint64_t //\nwuffs_base__ieee_754_bit_representation__from_f64(double f) {\n uint64_t u = 0;\n if (sizeof(uint64_t) == sizeof(double)) {\n memcpy(&u, &f, sizeof(uint64_t));\n }\n return u;\n}\n\nstatic inline double //\nwuffs_base__ieee_754_bit_representation__to_f64(uint64_t u) {\n double f = 0;\n if (sizeof(uint64_t) == sizeof(double)) {\n memcpy(&f, &u, sizeof(uint64_t));\n }\n return f;\n}\n\n " +
+ "" +
"// ---------------- Unicode and UTF-8\n\n#define WUFFS_BASE__UNICODE_CODE_POINT__MIN_INCL 0x00000000\n#define WUFFS_BASE__UNICODE_CODE_POINT__MAX_INCL 0x0010FFFF\n\n#define WUFFS_BASE__UNICODE_REPLACEMENT_CHARACTER 0x0000FFFD\n\n#define WUFFS_BASE__UNICODE_SURROGATE__MIN_INCL 0x0000D800\n#define WUFFS_BASE__UNICODE_SURROGATE__MAX_INCL 0x0000DFFF\n\n#define WUFFS_BASE__ASCII__MIN_INCL 0x00\n#define WUFFS_BASE__ASCII__MAX_INCL 0x7F\n\n#define WUFFS_BASE__UTF_8__BYTE_LENGTH__MIN_INCL 1\n#define WUFFS_BASE__UTF_8__BYTE_LENGTH__MAX_INCL 4\n\n#define WUFFS_BASE__UTF_8__BYTE_LENGTH_1__CODE_POINT__MIN_INCL 0x00000000\n#define WUFFS_BASE__UTF_8__BYTE_LENGTH_1__CODE_POINT__MAX_INCL 0x0000007F\n#define WUFFS_BASE__UTF_8__BYTE_LENGTH_2__CODE_POINT__MIN_INCL 0x00000080\n#define WUFFS_BASE__UTF_8__BYTE_LENGTH_2__CODE_POINT__MAX_INCL 0x000007FF\n#define WUFFS_BASE__UTF_8__BYTE_LENGTH_3__CODE_POINT__MIN_INCL 0x00000800\n#define WUFFS_BASE__UTF_8__BYTE_LENGTH_3__CODE_POINT__MAX_INCL 0x0000FFFF\n#define WUFFS_BASE__UTF_8__BYTE_LENGTH_4__CODE_POINT_" +
"_MIN_INCL 0x00010000\n#define WUFFS_BASE__UTF_8__BYTE_LENGTH_4__CODE_POINT__MAX_INCL 0x0010FFFF\n\n" +
"" +
"// --------\n\n// wuffs_base__utf_8__next__output is the type returned by\n// wuffs_base__utf_8__next.\ntypedef struct {\n uint32_t code_point;\n uint32_t byte_length;\n\n#ifdef __cplusplus\n inline bool is_valid() const;\n#endif // __cplusplus\n\n} wuffs_base__utf_8__next__output;\n\nstatic inline wuffs_base__utf_8__next__output //\nwuffs_base__make_utf_8__next__output(uint32_t code_point,\n uint32_t byte_length) {\n wuffs_base__utf_8__next__output ret;\n ret.code_point = code_point;\n ret.byte_length = byte_length;\n return ret;\n}\n\nstatic inline bool //\nwuffs_base__utf_8__next__output__is_valid(\n const wuffs_base__utf_8__next__output* o) {\n if (o) {\n uint32_t cp = o->code_point;\n switch (o->byte_length) {\n case 1:\n return (cp <= 0x7F);\n case 2:\n return (0x080 <= cp) && (cp <= 0x7FF);\n case 3:\n // Avoid the 0xD800 ..= 0xDFFF surrogate range.\n return ((0x0800 <= cp) && (cp <= 0xD7FF)) ||\n ((0xE000 <= cp) && (cp <= 0xF" +
"FFF));\n case 4:\n return (0x00010000 <= cp) && (cp <= 0x0010FFFF);\n }\n }\n return false;\n}\n\n#ifdef __cplusplus\n\ninline bool //\nwuffs_base__utf_8__next__output::is_valid() const {\n return wuffs_base__utf_8__next__output__is_valid(this);\n}\n\n#endif // __cplusplus\n\n" +
"" +
- "// --------\n\n// wuffs_base__utf_8__encode writes the UTF-8 encoding of code_point to s and\n// returns the number of bytes written. If code_point is invalid, or if s is\n// shorter than the entire encoding, it returns 0 (and no bytes are written).\n//\n// s will never be too short if its length is at least 4, also known as\n// WUFFS_BASE__UTF_8__BYTE_LENGTH__MAX_INCL.\nsize_t //\nwuffs_base__utf_8__encode(wuffs_base__slice_u8 dst, uint32_t code_point);\n\n// wuffs_base__utf_8__next returns the next UTF-8 code point (and that code\n// point's byte length) at the start of s.\n//\n// There are exactly two cases in which this function returns something where\n// wuffs_base__utf_8__next__output__is_valid is false:\n// - If s is empty then it returns {.code_point=0, .byte_length=0}.\n// - If s is non-empty and starts with invalid UTF-8 then it returns\n// {.code_point=WUFFS_BASE__UNICODE_REPLACEMENT_CHARACTER, .byte_length=1}.\n//\n// Otherwise, it returns something where\n// wuffs_base__utf_8__next__output__is_valid is true.\n//" +
- "\n// In any case, it always returns an output that satisfies both of:\n// - (output.code_point <= WUFFS_BASE__UNICODE_CODE_POINT__MAX_INCL).\n// - (output.byte_length <= s.len).\n//\n// If s is a sub-slice of a larger slice of valid UTF-8, but that sub-slice\n// boundary occurs in the middle of a multi-byte UTF-8 encoding of a single\n// code point, then this function may return something invalid. It is the\n// caller's responsibility to split on or otherwise manage UTF-8 boundaries.\nwuffs_base__utf_8__next__output //\nwuffs_base__utf_8__next(wuffs_base__slice_u8 s);\n\n// wuffs_base__utf_8__longest_valid_prefix returns the largest n such that the\n// sub-slice s[..n] is valid UTF-8.\n//\n// In particular, it returns s.len if and only if all of s is valid UTF-8.\n//\n// If s is a sub-slice of a larger slice of valid UTF-8, but that sub-slice\n// boundary occurs in the middle of a multi-byte UTF-8 encoding of a single\n// code point, then this function will return less than s.len. It is the\n// caller's responsibility to spl" +
- "it on or otherwise manage UTF-8 boundaries.\nsize_t //\nwuffs_base__utf_8__longest_valid_prefix(wuffs_base__slice_u8 s);\n\n// wuffs_base__ascii__longest_valid_prefix returns the largest n such that the\n// sub-slice s[..n] is valid ASCII.\n//\n// In particular, it returns s.len if and only if all of s is valid ASCII.\n// Equivalently, when none of the bytes in s have the 0x80 high bit set.\nsize_t //\nwuffs_base__ascii__longest_valid_prefix(wuffs_base__slice_u8 s);\n" +
+ "// --------\n\n// wuffs_base__utf_8__encode writes the UTF-8 encoding of code_point to s and\n// returns the number of bytes written. If code_point is invalid, or if s is\n// shorter than the entire encoding, it returns 0 (and no bytes are written).\n//\n// s will never be too short if its length is at least 4, also known as\n// WUFFS_BASE__UTF_8__BYTE_LENGTH__MAX_INCL.\nsize_t //\nwuffs_base__utf_8__encode(wuffs_base__slice_u8 dst, uint32_t code_point);\n\n// wuffs_base__utf_8__next returns the next UTF-8 code point (and that code\n// point's byte length) at the start of s.\n//\n// There are exactly two cases in which this function returns something where\n// wuffs_base__utf_8__next__output__is_valid is false:\n// - If s is empty then it returns {.code_point=0, .byte_length=0}.\n// - If s is non-empty and starts with invalid UTF-8 then it returns\n// {.code_point=WUFFS_BASE__UNICODE_REPLACEMENT_CHARACTER, .byte_length=1}.\n//\n// Otherwise, it returns something where\n// wuffs_base__utf_8__next__output__is_valid is true.\n/" +
+ "/\n// In any case, it always returns an output that satisfies both of:\n// - (output.code_point <= WUFFS_BASE__UNICODE_CODE_POINT__MAX_INCL).\n// - (output.byte_length <= s.len).\n//\n// If s is a sub-slice of a larger slice of valid UTF-8, but that sub-slice\n// boundary occurs in the middle of a multi-byte UTF-8 encoding of a single\n// code point, then this function may return something invalid. It is the\n// caller's responsibility to split on or otherwise manage UTF-8 boundaries.\nwuffs_base__utf_8__next__output //\nwuffs_base__utf_8__next(wuffs_base__slice_u8 s);\n\n// wuffs_base__utf_8__longest_valid_prefix returns the largest n such that the\n// sub-slice s[..n] is valid UTF-8.\n//\n// In particular, it returns s.len if and only if all of s is valid UTF-8.\n//\n// If s is a sub-slice of a larger slice of valid UTF-8, but that sub-slice\n// boundary occurs in the middle of a multi-byte UTF-8 encoding of a single\n// code point, then this function will return less than s.len. It is the\n// caller's responsibility to sp" +
+ "lit on or otherwise manage UTF-8 boundaries.\nsize_t //\nwuffs_base__utf_8__longest_valid_prefix(wuffs_base__slice_u8 s);\n\n// wuffs_base__ascii__longest_valid_prefix returns the largest n such that the\n// sub-slice s[..n] is valid ASCII.\n//\n// In particular, it returns s.len if and only if all of s is valid ASCII.\n// Equivalently, when none of the bytes in s have the 0x80 high bit set.\nsize_t //\nwuffs_base__ascii__longest_valid_prefix(wuffs_base__slice_u8 s);\n" +
""
const baseTokenPrivateH = "" +
diff --git a/release/c/wuffs-unsupported-snapshot.c b/release/c/wuffs-unsupported-snapshot.c
index 73cb5e2..d20542a 100644
--- a/release/c/wuffs-unsupported-snapshot.c
+++ b/release/c/wuffs-unsupported-snapshot.c
@@ -294,6 +294,7 @@
T value; \
}
+typedef WUFFS_BASE__RESULT(double) wuffs_base__result_f64;
typedef WUFFS_BASE__RESULT(int64_t) wuffs_base__result_i64;
typedef WUFFS_BASE__RESULT(uint64_t) wuffs_base__result_u64;
@@ -3433,7 +3434,73 @@
wuffs_base__result_u64 //
wuffs_base__parse_number_u64(wuffs_base__slice_u8 s);
-// ---------------- Unicode and UTF-8
+// ---------------- IEEE 754 Floating Point
+
+// wuffs_base__parse_number_f64 parses the floating point number in s. For
+// example, if s contains the bytes "1.5" then it will return the double 1.5.
+//
+// It returns an error if s does not contain a floating point number.
+//
+// It does not necessarily return an error if the conversion is lossy, e.g. if
+// s is "0.3", which double-precision floating point cannot represent exactly.
+//
+// Similarly, the returned value may be infinite (and no error returned) even
+// if s was not "inf", when the input is nominally finite but sufficiently
+// larger than DBL_MAX, about 1.8e+308.
+//
+// It is similar to the C standard library's strtod function, but:
+// - Errors are returned in-band (in a result type), not out-of-band (errno).
+// - It takes a slice (a pointer and length), not a NUL-terminated C string.
+// - It does not take an optional endptr argument. It does not allow a partial
+// parse: it returns an error unless all of s is consumed.
+// - It does not allow whitespace, leading or otherwise.
+// - It does not allow unnecessary leading zeroes ("0" is valid and its sole
+// zero is necessary). All of "00", "0644" and "00.7" are invalid.
+// - It is not affected by i18n / l10n settings such as environment variables.
+// - Conversely, it always accepts either ',' or '.' as a decimal separator.
+// In particular, "3,141,592" is always invalid but "3,141" is always valid
+// (and approximately π). The caller is responsible for e.g. previously
+// rejecting or filtering s if it contains a comma, if that is unacceptable
+// to the caller. For example, JSON numbers always use a dot '.' and never a
+// comma ',', regardless of the LOCALE environment variable.
+// - It does allow arbitrary underscores. For example, "_3.141_592" would
+// successfully parse, again approximately π.
+// - It does allow "inf", "+Infinity" and "-NAN", case insensitive, but it
+// does not permit "nan" to be followed by an integer mantissa.
+// - It does not allow hexadecimal floating point numbers.
+wuffs_base__result_f64 //
+wuffs_base__parse_number_f64(wuffs_base__slice_u8 s);
+
+// wuffs_base__ieee_754_bit_representation__etc converts between a double
+// precision numerical value and its IEEE 754 64-bit representation (1 sign
+// bit, 11 exponent bits, 52 explicit significand bits).
+//
+// For example, it converts between:
+// - +1.0 and 0x3FF0_0000_0000_0000.
+// - +5.5 and 0x4016_0000_0000_0000.
+// - -inf and 0xFFF0_0000_0000_0000.
+//
+// See https://en.wikipedia.org/wiki/Double-precision_floating-point_format
+
+static inline uint64_t //
+wuffs_base__ieee_754_bit_representation__from_f64(double f) {
+ uint64_t u = 0;
+ if (sizeof(uint64_t) == sizeof(double)) {
+ memcpy(&u, &f, sizeof(uint64_t));
+ }
+ return u;
+}
+
+static inline double //
+wuffs_base__ieee_754_bit_representation__to_f64(uint64_t u) {
+ double f = 0;
+ if (sizeof(uint64_t) == sizeof(double)) {
+ memcpy(&f, &u, sizeof(uint64_t));
+ }
+ return f;
+}
+
+ // ---------------- Unicode and UTF-8
#define WUFFS_BASE__UNICODE_CODE_POINT__MIN_INCL 0x00000000
#define WUFFS_BASE__UNICODE_CODE_POINT__MAX_INCL 0x0010FFFF
@@ -8620,6 +8687,811 @@
} while (0);
}
+ // ---------------- IEEE 754 Floating Point
+
+#define WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DECIMAL_POINT__RANGE 1023
+#define WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DIGITS_PRECISION 500
+
+// WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__SHIFT__MAX_INCL is the largest N
+// such that ((10 << N) < (1 << 64)).
+#define WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__SHIFT__MAX_INCL 60
+
+// wuffs_base__private_implementation__high_prec_dec (abbreviated as HPD) is a
+// fixed precision floating point decimal number, augmented with ±infinity
+// values, but it cannot represent NaN (Not a Number).
+//
+// 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
+// WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DIGITS_PRECISION and
+// WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DECIMAL_POINT__RANGE.
+//
+// digits[.. num_digits] are the number's digits in big-endian order. The
+// uint8_t values are in the range [0 ..= 9], not ['0' ..= '9'], where e.g. '7'
+// is the ASCII value 0x37.
+//
+// decimal_point is the index (within digits) of the decimal point. It may be
+// negative or be larger than num_digits, in which case the explicit digits are
+// padded with implicit zeroes.
+//
+// For example, if num_digits is 3 and digits is "\x07\x08\x09":
+// - A decimal_point of -2 means ".00789"
+// - A decimal_point of -1 means ".0789"
+// - A decimal_point of -0 means ".789"
+// - A decimal_point of +1 means "7.89"
+// - A decimal_point of +2 means "78.9"
+// - A decimal_point of +3 means "789."
+// - 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.
+//
+// negative is a sign bit. An HPD can distinguish positive and negative zero.
+//
+// truncated is whether there are more than
+// WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DIGITS_PRECISION digits, and at
+// least one of those extra digits are non-zero. The existence of long-tail
+// digits can affect rounding.
+//
+// The "all fields are zero" value is valid, and represents the number +0.
+typedef struct {
+ uint32_t num_digits;
+ int32_t decimal_point;
+ bool negative;
+ bool truncated;
+ uint8_t digits[WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DIGITS_PRECISION];
+} wuffs_base__private_implementation__high_prec_dec;
+
+// wuffs_base__private_implementation__high_prec_dec__trim trims trailing
+// zeroes from the h->digits[.. h->num_digits] slice. They have no benefit,
+// since we explicitly track h->decimal_point.
+//
+// Preconditions:
+// - h is non-NULL.
+static inline void //
+wuffs_base__private_implementation__high_prec_dec__trim(
+ wuffs_base__private_implementation__high_prec_dec* h) {
+ while ((h->num_digits > 0) && (h->digits[h->num_digits - 1] == 0)) {
+ h->num_digits--;
+ }
+}
+
+static wuffs_base__status //
+wuffs_base__private_implementation__high_prec_dec__parse(
+ wuffs_base__private_implementation__high_prec_dec* h,
+ wuffs_base__slice_u8 s) {
+ if (!h) {
+ return wuffs_base__make_status(wuffs_base__error__bad_receiver);
+ }
+ h->num_digits = 0;
+ h->decimal_point = 0;
+ h->negative = false;
+ h->truncated = false;
+
+ uint8_t* p = s.ptr;
+ uint8_t* q = s.ptr + s.len;
+
+ for (; (p < q) && (*p == '_'); p++) {
+ }
+ if (p >= q) {
+ return wuffs_base__make_status(wuffs_base__error__bad_argument);
+ }
+
+ // Parse sign.
+ do {
+ if (*p == '+') {
+ p++;
+ } else if (*p == '-') {
+ h->negative = true;
+ p++;
+ } else {
+ break;
+ }
+ for (; (p < q) && (*p == '_'); p++) {
+ }
+ } while (0);
+
+ // Parse digits.
+ uint32_t nd = 0;
+ int32_t dp = 0;
+ bool saw_digits = false;
+ bool saw_non_zero_digits = false;
+ bool saw_dot = false;
+ for (; p < q; p++) {
+ if (*p == '_') {
+ // No-op.
+
+ } else if ((*p == '.') || (*p == ',')) {
+ // As per https://en.wikipedia.org/wiki/Decimal_separator, both '.' or
+ // ',' are commonly used. We just parse either, regardless of LOCALE.
+ if (saw_dot) {
+ return wuffs_base__make_status(wuffs_base__error__bad_argument);
+ }
+ saw_dot = true;
+ dp = (int32_t)nd;
+
+ } else if ('0' == *p) {
+ if (!saw_dot && !saw_non_zero_digits && saw_digits) {
+ // We don't allow unnecessary leading zeroes: "000123" or "0644".
+ return wuffs_base__make_status(wuffs_base__error__bad_argument);
+ }
+ saw_digits = true;
+ if (nd == 0) {
+ // Track leading zeroes implicitly.
+ dp--;
+ } else if (nd <
+ WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DIGITS_PRECISION) {
+ h->digits[nd++] = 0;
+ } else {
+ // Long-tail zeroes are ignored.
+ }
+
+ } else if (('0' < *p) && (*p <= '9')) {
+ if (!saw_dot && !saw_non_zero_digits && saw_digits) {
+ // We don't allow unnecessary leading zeroes: "000123" or "0644".
+ return wuffs_base__make_status(wuffs_base__error__bad_argument);
+ }
+ saw_digits = true;
+ saw_non_zero_digits = true;
+ if (nd < WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DIGITS_PRECISION) {
+ h->digits[nd++] = (uint8_t)(*p - '0');
+ } else {
+ // Long-tail non-zeroes set the truncated bit.
+ h->truncated = true;
+ }
+
+ } else {
+ break;
+ }
+ }
+
+ if (!saw_digits) {
+ return wuffs_base__make_status(wuffs_base__error__bad_argument);
+ }
+ if (!saw_dot) {
+ dp = (int32_t)nd;
+ }
+
+ // Parse exponent.
+ if ((p < q) && ((*p == 'E') || (*p == 'e'))) {
+ p++;
+ for (; (p < q) && (*p == '_'); p++) {
+ }
+ if (p >= q) {
+ return wuffs_base__make_status(wuffs_base__error__bad_argument);
+ }
+
+ int32_t exp_sign = +1;
+ if (*p == '+') {
+ p++;
+ } else if (*p == '-') {
+ exp_sign = -1;
+ p++;
+ }
+
+ int32_t exp = 0;
+ const int32_t exp_large =
+ WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DECIMAL_POINT__RANGE +
+ WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DIGITS_PRECISION;
+ bool saw_exp_digits = false;
+ for (; p < q; p++) {
+ if (*p == '_') {
+ // No-op.
+ } else if (('0' <= *p) && (*p <= '9')) {
+ saw_exp_digits = true;
+ if (exp < exp_large) {
+ exp = (10 * exp) + ((int32_t)(*p - '0'));
+ }
+ } else {
+ break;
+ }
+ }
+ if (!saw_exp_digits) {
+ return wuffs_base__make_status(wuffs_base__error__bad_argument);
+ }
+ dp += exp_sign * exp;
+ }
+
+ // Finish.
+ if (p != q) {
+ return wuffs_base__make_status(wuffs_base__error__bad_argument);
+ }
+ h->num_digits = nd;
+ if (nd == 0) {
+ h->decimal_point = 0;
+ } else if (dp <
+ -WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DECIMAL_POINT__RANGE) {
+ h->decimal_point =
+ -WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DECIMAL_POINT__RANGE - 1;
+ } else if (dp >
+ +WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DECIMAL_POINT__RANGE) {
+ h->decimal_point =
+ +WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DECIMAL_POINT__RANGE + 1;
+ } else {
+ h->decimal_point = dp;
+ }
+ wuffs_base__private_implementation__high_prec_dec__trim(h);
+ return wuffs_base__make_status(NULL);
+}
+
+// --------
+
+// The etc__hpd_left_shift and etc__powers_of_5 tables were printed by
+// script/print-hpd-left-shift.go. That script has an optional -comments flag,
+// whose output is not copied here, which prints further detail.
+//
+// These tables are used in
+// wuffs_base__private_implementation__high_prec_dec__lshift_num_new_digits.
+
+// wuffs_base__private_implementation__hpd_left_shift[i] encodes the number of
+// new digits created after multiplying a positive integer by (1 << i): the
+// additional length in the decimal representation. For example, shifting "234"
+// by 3 (equivalent to multiplying by 8) will produce "1872". Going from a
+// 3-length string to a 4-length string means that 1 new digit was added (and
+// existing digits may have changed).
+//
+// Shifting by i can add either N or N-1 new digits, depending on whether the
+// original positive integer compares >= or < to the i'th power of 5 (as 10
+// equals 2 * 5). Comparison is lexicographic, not numerical.
+//
+// For example, shifting by 4 (i.e. multiplying by 16) can add 1 or 2 new
+// digits, depending on a lexicographic comparison to (5 ** 4), i.e. "625":
+// - ("1" << 4) is "16", which adds 1 new digit.
+// - ("5678" << 4) is "90848", which adds 1 new digit.
+// - ("624" << 4) is "9984", which adds 1 new digit.
+// - ("62498" << 4) is "999968", which adds 1 new digit.
+// - ("625" << 4) is "10000", which adds 2 new digits.
+// - ("625001" << 4) is "10000016", which adds 2 new digits.
+// - ("7008" << 4) is "112128", which adds 2 new digits.
+// - ("99" << 4) is "1584", which adds 2 new digits.
+//
+// Thus, when i is 4, N is 2 and (5 ** i) is "625". This etc__hpd_left_shift
+// array encodes this as:
+// - etc__hpd_left_shift[4] is 0x1006 = (2 << 11) | 0x0006.
+// - etc__hpd_left_shift[5] is 0x1009 = (? << 11) | 0x0009.
+// where the ? isn't relevant for i == 4.
+//
+// The high 5 bits of etc__hpd_left_shift[i] is N, the higher of the two
+// possible number of new digits. The low 11 bits are an offset into the
+// etc__powers_of_5 array (of length 0x051C, so offsets fit in 11 bits). When i
+// is 4, its offset and the next one is 6 and 9, and etc__powers_of_5[6 .. 9]
+// is the string "\x06\x02\x05", so the relevant power of 5 is "625".
+//
+// Thanks to Ken Thompson for the original idea.
+static const uint16_t wuffs_base__private_implementation__hpd_left_shift[65] = {
+ 0x0000, 0x0800, 0x0801, 0x0803, 0x1006, 0x1009, 0x100D, 0x1812, 0x1817,
+ 0x181D, 0x2024, 0x202B, 0x2033, 0x203C, 0x2846, 0x2850, 0x285B, 0x3067,
+ 0x3073, 0x3080, 0x388E, 0x389C, 0x38AB, 0x38BB, 0x40CC, 0x40DD, 0x40EF,
+ 0x4902, 0x4915, 0x4929, 0x513E, 0x5153, 0x5169, 0x5180, 0x5998, 0x59B0,
+ 0x59C9, 0x61E3, 0x61FD, 0x6218, 0x6A34, 0x6A50, 0x6A6D, 0x6A8B, 0x72AA,
+ 0x72C9, 0x72E9, 0x7B0A, 0x7B2B, 0x7B4D, 0x8370, 0x8393, 0x83B7, 0x83DC,
+ 0x8C02, 0x8C28, 0x8C4F, 0x9477, 0x949F, 0x94C8, 0x9CF2, 0x051C, 0x051C,
+ 0x051C, 0x051C,
+};
+
+// wuffs_base__private_implementation__powers_of_5 contains the powers of 5,
+// concatenated together: "5", "25", "125", "625", "3125", etc.
+static const uint8_t wuffs_base__private_implementation__powers_of_5[0x051C] = {
+ 5, 2, 5, 1, 2, 5, 6, 2, 5, 3, 1, 2, 5, 1, 5, 6, 2, 5, 7, 8, 1, 2, 5, 3, 9,
+ 0, 6, 2, 5, 1, 9, 5, 3, 1, 2, 5, 9, 7, 6, 5, 6, 2, 5, 4, 8, 8, 2, 8, 1, 2,
+ 5, 2, 4, 4, 1, 4, 0, 6, 2, 5, 1, 2, 2, 0, 7, 0, 3, 1, 2, 5, 6, 1, 0, 3, 5,
+ 1, 5, 6, 2, 5, 3, 0, 5, 1, 7, 5, 7, 8, 1, 2, 5, 1, 5, 2, 5, 8, 7, 8, 9, 0,
+ 6, 2, 5, 7, 6, 2, 9, 3, 9, 4, 5, 3, 1, 2, 5, 3, 8, 1, 4, 6, 9, 7, 2, 6, 5,
+ 6, 2, 5, 1, 9, 0, 7, 3, 4, 8, 6, 3, 2, 8, 1, 2, 5, 9, 5, 3, 6, 7, 4, 3, 1,
+ 6, 4, 0, 6, 2, 5, 4, 7, 6, 8, 3, 7, 1, 5, 8, 2, 0, 3, 1, 2, 5, 2, 3, 8, 4,
+ 1, 8, 5, 7, 9, 1, 0, 1, 5, 6, 2, 5, 1, 1, 9, 2, 0, 9, 2, 8, 9, 5, 5, 0, 7,
+ 8, 1, 2, 5, 5, 9, 6, 0, 4, 6, 4, 4, 7, 7, 5, 3, 9, 0, 6, 2, 5, 2, 9, 8, 0,
+ 2, 3, 2, 2, 3, 8, 7, 6, 9, 5, 3, 1, 2, 5, 1, 4, 9, 0, 1, 1, 6, 1, 1, 9, 3,
+ 8, 4, 7, 6, 5, 6, 2, 5, 7, 4, 5, 0, 5, 8, 0, 5, 9, 6, 9, 2, 3, 8, 2, 8, 1,
+ 2, 5, 3, 7, 2, 5, 2, 9, 0, 2, 9, 8, 4, 6, 1, 9, 1, 4, 0, 6, 2, 5, 1, 8, 6,
+ 2, 6, 4, 5, 1, 4, 9, 2, 3, 0, 9, 5, 7, 0, 3, 1, 2, 5, 9, 3, 1, 3, 2, 2, 5,
+ 7, 4, 6, 1, 5, 4, 7, 8, 5, 1, 5, 6, 2, 5, 4, 6, 5, 6, 6, 1, 2, 8, 7, 3, 0,
+ 7, 7, 3, 9, 2, 5, 7, 8, 1, 2, 5, 2, 3, 2, 8, 3, 0, 6, 4, 3, 6, 5, 3, 8, 6,
+ 9, 6, 2, 8, 9, 0, 6, 2, 5, 1, 1, 6, 4, 1, 5, 3, 2, 1, 8, 2, 6, 9, 3, 4, 8,
+ 1, 4, 4, 5, 3, 1, 2, 5, 5, 8, 2, 0, 7, 6, 6, 0, 9, 1, 3, 4, 6, 7, 4, 0, 7,
+ 2, 2, 6, 5, 6, 2, 5, 2, 9, 1, 0, 3, 8, 3, 0, 4, 5, 6, 7, 3, 3, 7, 0, 3, 6,
+ 1, 3, 2, 8, 1, 2, 5, 1, 4, 5, 5, 1, 9, 1, 5, 2, 2, 8, 3, 6, 6, 8, 5, 1, 8,
+ 0, 6, 6, 4, 0, 6, 2, 5, 7, 2, 7, 5, 9, 5, 7, 6, 1, 4, 1, 8, 3, 4, 2, 5, 9,
+ 0, 3, 3, 2, 0, 3, 1, 2, 5, 3, 6, 3, 7, 9, 7, 8, 8, 0, 7, 0, 9, 1, 7, 1, 2,
+ 9, 5, 1, 6, 6, 0, 1, 5, 6, 2, 5, 1, 8, 1, 8, 9, 8, 9, 4, 0, 3, 5, 4, 5, 8,
+ 5, 6, 4, 7, 5, 8, 3, 0, 0, 7, 8, 1, 2, 5, 9, 0, 9, 4, 9, 4, 7, 0, 1, 7, 7,
+ 2, 9, 2, 8, 2, 3, 7, 9, 1, 5, 0, 3, 9, 0, 6, 2, 5, 4, 5, 4, 7, 4, 7, 3, 5,
+ 0, 8, 8, 6, 4, 6, 4, 1, 1, 8, 9, 5, 7, 5, 1, 9, 5, 3, 1, 2, 5, 2, 2, 7, 3,
+ 7, 3, 6, 7, 5, 4, 4, 3, 2, 3, 2, 0, 5, 9, 4, 7, 8, 7, 5, 9, 7, 6, 5, 6, 2,
+ 5, 1, 1, 3, 6, 8, 6, 8, 3, 7, 7, 2, 1, 6, 1, 6, 0, 2, 9, 7, 3, 9, 3, 7, 9,
+ 8, 8, 2, 8, 1, 2, 5, 5, 6, 8, 4, 3, 4, 1, 8, 8, 6, 0, 8, 0, 8, 0, 1, 4, 8,
+ 6, 9, 6, 8, 9, 9, 4, 1, 4, 0, 6, 2, 5, 2, 8, 4, 2, 1, 7, 0, 9, 4, 3, 0, 4,
+ 0, 4, 0, 0, 7, 4, 3, 4, 8, 4, 4, 9, 7, 0, 7, 0, 3, 1, 2, 5, 1, 4, 2, 1, 0,
+ 8, 5, 4, 7, 1, 5, 2, 0, 2, 0, 0, 3, 7, 1, 7, 4, 2, 2, 4, 8, 5, 3, 5, 1, 5,
+ 6, 2, 5, 7, 1, 0, 5, 4, 2, 7, 3, 5, 7, 6, 0, 1, 0, 0, 1, 8, 5, 8, 7, 1, 1,
+ 2, 4, 2, 6, 7, 5, 7, 8, 1, 2, 5, 3, 5, 5, 2, 7, 1, 3, 6, 7, 8, 8, 0, 0, 5,
+ 0, 0, 9, 2, 9, 3, 5, 5, 6, 2, 1, 3, 3, 7, 8, 9, 0, 6, 2, 5, 1, 7, 7, 6, 3,
+ 5, 6, 8, 3, 9, 4, 0, 0, 2, 5, 0, 4, 6, 4, 6, 7, 7, 8, 1, 0, 6, 6, 8, 9, 4,
+ 5, 3, 1, 2, 5, 8, 8, 8, 1, 7, 8, 4, 1, 9, 7, 0, 0, 1, 2, 5, 2, 3, 2, 3, 3,
+ 8, 9, 0, 5, 3, 3, 4, 4, 7, 2, 6, 5, 6, 2, 5, 4, 4, 4, 0, 8, 9, 2, 0, 9, 8,
+ 5, 0, 0, 6, 2, 6, 1, 6, 1, 6, 9, 4, 5, 2, 6, 6, 7, 2, 3, 6, 3, 2, 8, 1, 2,
+ 5, 2, 2, 2, 0, 4, 4, 6, 0, 4, 9, 2, 5, 0, 3, 1, 3, 0, 8, 0, 8, 4, 7, 2, 6,
+ 3, 3, 3, 6, 1, 8, 1, 6, 4, 0, 6, 2, 5, 1, 1, 1, 0, 2, 2, 3, 0, 2, 4, 6, 2,
+ 5, 1, 5, 6, 5, 4, 0, 4, 2, 3, 6, 3, 1, 6, 6, 8, 0, 9, 0, 8, 2, 0, 3, 1, 2,
+ 5, 5, 5, 5, 1, 1, 1, 5, 1, 2, 3, 1, 2, 5, 7, 8, 2, 7, 0, 2, 1, 1, 8, 1, 5,
+ 8, 3, 4, 0, 4, 5, 4, 1, 0, 1, 5, 6, 2, 5, 2, 7, 7, 5, 5, 5, 7, 5, 6, 1, 5,
+ 6, 2, 8, 9, 1, 3, 5, 1, 0, 5, 9, 0, 7, 9, 1, 7, 0, 2, 2, 7, 0, 5, 0, 7, 8,
+ 1, 2, 5, 1, 3, 8, 7, 7, 7, 8, 7, 8, 0, 7, 8, 1, 4, 4, 5, 6, 7, 5, 5, 2, 9,
+ 5, 3, 9, 5, 8, 5, 1, 1, 3, 5, 2, 5, 3, 9, 0, 6, 2, 5, 6, 9, 3, 8, 8, 9, 3,
+ 9, 0, 3, 9, 0, 7, 2, 2, 8, 3, 7, 7, 6, 4, 7, 6, 9, 7, 9, 2, 5, 5, 6, 7, 6,
+ 2, 6, 9, 5, 3, 1, 2, 5, 3, 4, 6, 9, 4, 4, 6, 9, 5, 1, 9, 5, 3, 6, 1, 4, 1,
+ 8, 8, 8, 2, 3, 8, 4, 8, 9, 6, 2, 7, 8, 3, 8, 1, 3, 4, 7, 6, 5, 6, 2, 5, 1,
+ 7, 3, 4, 7, 2, 3, 4, 7, 5, 9, 7, 6, 8, 0, 7, 0, 9, 4, 4, 1, 1, 9, 2, 4, 4,
+ 8, 1, 3, 9, 1, 9, 0, 6, 7, 3, 8, 2, 8, 1, 2, 5, 8, 6, 7, 3, 6, 1, 7, 3, 7,
+ 9, 8, 8, 4, 0, 3, 5, 4, 7, 2, 0, 5, 9, 6, 2, 2, 4, 0, 6, 9, 5, 9, 5, 3, 3,
+ 6, 9, 1, 4, 0, 6, 2, 5,
+};
+
+// wuffs_base__private_implementation__high_prec_dec__lshift_num_new_digits
+// returns the number of additional decimal digits when left-shifting by shift.
+//
+// See below for preconditions.
+static uint32_t //
+wuffs_base__private_implementation__high_prec_dec__lshift_num_new_digits(
+ wuffs_base__private_implementation__high_prec_dec* h,
+ uint32_t shift) {
+ // Masking with 0x3F should be unnecessary (assuming the preconditions) but
+ // it's cheap and ensures that we don't overflow the
+ // wuffs_base__private_implementation__hpd_left_shift array.
+ shift &= 63;
+
+ uint32_t x_a = wuffs_base__private_implementation__hpd_left_shift[shift];
+ uint32_t x_b = wuffs_base__private_implementation__hpd_left_shift[shift + 1];
+ uint32_t num_new_digits = x_a >> 11;
+ uint32_t pow5_a = 0x7FF & x_a;
+ uint32_t pow5_b = 0x7FF & x_b;
+
+ const uint8_t* pow5 =
+ &wuffs_base__private_implementation__powers_of_5[pow5_a];
+ uint32_t i = 0;
+ uint32_t n = pow5_b - pow5_a;
+ for (; i < n; i++) {
+ if (i >= h->num_digits) {
+ return num_new_digits - 1;
+ } else if (h->digits[i] == pow5[i]) {
+ continue;
+ } else if (h->digits[i] < pow5[i]) {
+ return num_new_digits - 1;
+ } else {
+ return num_new_digits;
+ }
+ }
+ return num_new_digits;
+}
+
+// --------
+
+// wuffs_base__private_implementation__high_prec_dec__rounded_integer returns
+// the integral (non-fractional) part of h, provided that it is 18 or fewer
+// decimal digits. For 19 or more digits, it returns UINT64_MAX. Note that:
+// - (1 << 53) is 9007199254740992, which has 16 decimal digits.
+// - (1 << 56) is 72057594037927936, which has 17 decimal digits.
+// - (1 << 59) is 576460752303423488, which has 18 decimal digits.
+// - (1 << 63) is 9223372036854775808, which has 19 decimal digits.
+// and that IEEE 754 double precision has 52 mantissa bits.
+//
+// That integral part is rounded-to-even: rounding 7.5 or 8.5 both give 8.
+//
+// h's negative bit is ignored: rounding -8.6 returns 9.
+//
+// See below for preconditions.
+static uint64_t //
+wuffs_base__private_implementation__high_prec_dec__rounded_integer(
+ wuffs_base__private_implementation__high_prec_dec* h) {
+ if ((h->num_digits == 0) || (h->decimal_point < 0)) {
+ return 0;
+ } else if (h->decimal_point > 18) {
+ return UINT64_MAX;
+ }
+
+ uint32_t dp = (uint32_t)(h->decimal_point);
+ uint64_t n = 0;
+ uint32_t i = 0;
+ for (; i < dp; i++) {
+ n = (10 * n) + ((i < h->num_digits) ? h->digits[i] : 0);
+ }
+
+ bool round_up = false;
+ if (dp < h->num_digits) {
+ round_up = h->digits[dp] >= 5;
+ if ((h->digits[dp] == 5) && (dp + 1 == h->num_digits)) {
+ // We are exactly halfway. If we're truncated, round up, otherwise round
+ // to even.
+ round_up = h->truncated || //
+ ((dp > 0) && (1 & h->digits[dp - 1]));
+ }
+ }
+ if (round_up) {
+ n++;
+ }
+
+ return n;
+}
+
+// wuffs_base__private_implementation__high_prec_dec__small_xshift shifts h's
+// number (where 'x' is 'l' or 'r' for left or right) by a small shift value.
+//
+// Preconditions:
+// - h is non-NULL.
+// - h->decimal_point is "not extreme".
+// - shift is non-zero.
+// - shift is "a small shift".
+//
+// "Not extreme" means within
+// ±WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DECIMAL_POINT__RANGE.
+//
+// "A small shift" means not more than
+// WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__SHIFT__MAX_INCL.
+//
+// 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.
+
+static void //
+wuffs_base__private_implementation__high_prec_dec__small_lshift(
+ wuffs_base__private_implementation__high_prec_dec* h,
+ uint32_t shift) {
+ if (h->num_digits == 0) {
+ return;
+ }
+ uint32_t num_new_digits =
+ wuffs_base__private_implementation__high_prec_dec__lshift_num_new_digits(
+ h, shift);
+ uint32_t rx = h->num_digits - 1; // Read index.
+ uint32_t wx = h->num_digits - 1 + num_new_digits; // Write index.
+ uint64_t n = 0;
+
+ // Repeat: pick up a digit, put down a digit, right to left.
+ while (((int32_t)rx) >= 0) {
+ n += ((uint64_t)(h->digits[rx])) << shift;
+ uint64_t quo = n / 10;
+ uint64_t rem = n - (10 * quo);
+ if (wx < WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DIGITS_PRECISION) {
+ h->digits[wx] = (uint8_t)rem;
+ } else if (rem > 0) {
+ h->truncated = true;
+ }
+ n = quo;
+ wx--;
+ rx--;
+ }
+
+ // Put down leading digits, right to left.
+ while (n > 0) {
+ uint64_t quo = n / 10;
+ uint64_t rem = n - (10 * quo);
+ if (wx < WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DIGITS_PRECISION) {
+ h->digits[wx] = (uint8_t)rem;
+ } else if (rem > 0) {
+ h->truncated = true;
+ }
+ n = quo;
+ wx--;
+ }
+
+ // Finish.
+ h->num_digits += num_new_digits;
+ if (h->num_digits >
+ WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DIGITS_PRECISION) {
+ h->num_digits = WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DIGITS_PRECISION;
+ }
+ h->decimal_point += (int32_t)num_new_digits;
+ wuffs_base__private_implementation__high_prec_dec__trim(h);
+}
+
+static void //
+wuffs_base__private_implementation__high_prec_dec__small_rshift(
+ wuffs_base__private_implementation__high_prec_dec* h,
+ uint32_t shift) {
+ uint32_t rx = 0; // Read index.
+ uint32_t wx = 0; // Write index.
+ uint64_t n = 0;
+
+ // Pick up enough leading digits to cover the first shift.
+ while ((n >> shift) == 0) {
+ if (rx < h->num_digits) {
+ // Read a digit.
+ n = (10 * n) + h->digits[rx++];
+ } else if (n == 0) {
+ // h's number used to be zero and remains zero.
+ return;
+ } else {
+ // Read sufficient implicit trailing zeroes.
+ while ((n >> shift) == 0) {
+ n = 10 * n;
+ rx++;
+ }
+ break;
+ }
+ }
+ h->decimal_point -= ((int32_t)(rx - 1));
+ if (h->decimal_point <
+ -WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DECIMAL_POINT__RANGE) {
+ // After the shift, h's number is effectively zero.
+ h->num_digits = 0;
+ h->decimal_point = 0;
+ h->negative = false;
+ h->truncated = false;
+ return;
+ }
+
+ // Repeat: pick up a digit, put down a digit, left to right.
+ uint64_t mask = (((uint64_t)(1)) << shift) - 1;
+ while (rx < h->num_digits) {
+ uint8_t new_digit = ((uint8_t)(n >> shift));
+ n = (10 * (n & mask)) + h->digits[rx++];
+ h->digits[wx++] = new_digit;
+ }
+
+ // Put down trailing digits, left to right.
+ while (n > 0) {
+ uint8_t new_digit = ((uint8_t)(n >> shift));
+ n = 10 * (n & mask);
+ if (wx < WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DIGITS_PRECISION) {
+ h->digits[wx++] = new_digit;
+ } else if (new_digit > 0) {
+ h->truncated = true;
+ }
+ }
+
+ // Finish.
+ h->num_digits = wx;
+ wuffs_base__private_implementation__high_prec_dec__trim(h);
+}
+
+// --------
+
+wuffs_base__result_f64 //
+wuffs_base__parse_number_f64_special(wuffs_base__slice_u8 s,
+ const char* fallback_status_repr) {
+ do {
+ uint8_t* p = s.ptr;
+ uint8_t* q = s.ptr + s.len;
+
+ for (; (p < q) && (*p == '_'); p++) {
+ }
+ if (p >= q) {
+ goto fallback;
+ }
+
+ // Parse sign.
+ bool negative = false;
+ do {
+ if (*p == '+') {
+ p++;
+ } else if (*p == '-') {
+ negative = true;
+ p++;
+ } else {
+ break;
+ }
+ for (; (p < q) && (*p == '_'); p++) {
+ }
+ } while (0);
+ if (p >= q) {
+ goto fallback;
+ }
+
+ bool nan = false;
+ switch (p[0]) {
+ case 'I':
+ case 'i':
+ if (((q - p) < 3) || //
+ ((p[1] != 'N') && (p[1] != 'n')) || //
+ ((p[2] != 'F') && (p[2] != 'f'))) {
+ goto fallback;
+ }
+ p += 3;
+
+ if ((p >= q) || (*p == '_')) {
+ break;
+ } else if (((q - p) < 5) || //
+ ((p[0] != 'I') && (p[0] != 'i')) || //
+ ((p[1] != 'N') && (p[1] != 'n')) || //
+ ((p[2] != 'I') && (p[2] != 'i')) || //
+ ((p[3] != 'T') && (p[3] != 't')) || //
+ ((p[4] != 'Y') && (p[4] != 'y'))) {
+ goto fallback;
+ }
+ p += 5;
+
+ if ((p >= q) || (*p == '_')) {
+ break;
+ }
+ goto fallback;
+
+ case 'N':
+ case 'n':
+ if (((q - p) < 3) || //
+ ((p[1] != 'A') && (p[1] != 'a')) || //
+ ((p[2] != 'N') && (p[2] != 'n'))) {
+ goto fallback;
+ }
+ p += 3;
+
+ if ((p >= q) || (*p == '_')) {
+ nan = true;
+ break;
+ }
+ goto fallback;
+
+ default:
+ goto fallback;
+ }
+
+ // Finish.
+ for (; (p < q) && (*p == '_'); p++) {
+ }
+ if (p != q) {
+ goto fallback;
+ }
+ wuffs_base__result_f64 ret;
+ ret.status.repr = NULL;
+ ret.value = wuffs_base__ieee_754_bit_representation__to_f64(
+ (nan ? 0x7FFFFFFFFFFFFFFF : 0x7FF0000000000000) |
+ (negative ? 0x8000000000000000 : 0));
+ return ret;
+ } while (0);
+
+fallback:
+ do {
+ wuffs_base__result_f64 ret;
+ ret.status.repr = fallback_status_repr;
+ ret.value = 0;
+ return ret;
+ } while (0);
+}
+
+wuffs_base__result_f64 //
+wuffs_base__parse_number_f64(wuffs_base__slice_u8 s) {
+ wuffs_base__private_implementation__high_prec_dec h;
+
+ do {
+ // powers converts decimal powers of 10 to binary powers of 2. For example,
+ // (10000 >> 13) is 1. It stops before the elements exceed 60, also known
+ // as WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__SHIFT__MAX_INCL.
+ static const uint32_t num_powers = 19;
+ static const uint8_t powers[19] = {
+ 0, 3, 6, 9, 13, 16, 19, 23, 26, 29, //
+ 33, 36, 39, 43, 46, 49, 53, 56, 59, //
+ };
+
+ wuffs_base__status status =
+ wuffs_base__private_implementation__high_prec_dec__parse(&h, s);
+ if (status.repr) {
+ return wuffs_base__parse_number_f64_special(s, status.repr);
+ }
+
+ // Handle zero and obvious extremes. The largest and smallest positive
+ // finite f64 values are approximately 1.8e+308 and 4.9e-324.
+ if ((h.num_digits == 0) || (h.decimal_point < -326)) {
+ goto zero;
+ } else if (h.decimal_point > 310) {
+ goto infinity;
+ }
+
+ // Scale by powers of 2 until we're in the range [½ .. 1], which gives us
+ // our exponent (in base-2). First we shift right, possibly a little too
+ // far, ending with a value certainly below 1 and possibly below ½...
+ const int32_t bias = -1023;
+ int32_t exp2 = 0;
+ while (h.decimal_point > 0) {
+ uint32_t n = (uint32_t)(+h.decimal_point);
+ uint32_t shift =
+ (n < num_powers)
+ ? powers[n]
+ : WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__SHIFT__MAX_INCL;
+
+ wuffs_base__private_implementation__high_prec_dec__small_rshift(&h,
+ shift);
+ if (h.decimal_point <
+ -WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DECIMAL_POINT__RANGE) {
+ goto zero;
+ }
+ exp2 += (int32_t)shift;
+ }
+ // ...then we shift left, putting us in [½ .. 1].
+ while (h.decimal_point <= 0) {
+ uint32_t shift;
+ if (h.decimal_point == 0) {
+ if (h.digits[0] >= 5) {
+ break;
+ }
+ shift = (h.digits[0] <= 2) ? 2 : 1;
+ } else {
+ uint32_t n = (uint32_t)(-h.decimal_point);
+ shift = (n < num_powers)
+ ? powers[n]
+ : WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__SHIFT__MAX_INCL;
+ }
+
+ wuffs_base__private_implementation__high_prec_dec__small_lshift(&h,
+ shift);
+ if (h.decimal_point >
+ +WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DECIMAL_POINT__RANGE) {
+ goto infinity;
+ }
+ exp2 -= (int32_t)shift;
+ }
+
+ // We're in the range [½ .. 1] but f64 uses [1 .. 2].
+ exp2--;
+
+ // The minimum normal exponent is (bias + 1).
+ while ((bias + 1) > exp2) {
+ uint32_t n = (uint32_t)((bias + 1) - exp2);
+ if (n > WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__SHIFT__MAX_INCL) {
+ n = WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__SHIFT__MAX_INCL;
+ }
+ wuffs_base__private_implementation__high_prec_dec__small_rshift(&h, n);
+ exp2 += (int32_t)n;
+ }
+
+ // Check for overflow.
+ if ((exp2 - bias) >= 0x07FF) { // (1 << 11) - 1.
+ goto infinity;
+ }
+
+ // Extract 53 bits for the mantissa (in base-2).
+ wuffs_base__private_implementation__high_prec_dec__small_lshift(&h, 53);
+ uint64_t man2 =
+ wuffs_base__private_implementation__high_prec_dec__rounded_integer(&h);
+
+ // Rounding might have added one bit. If so, shift and re-check overflow.
+ if ((man2 >> 53) != 0) {
+ man2 >>= 1;
+ exp2++;
+ if ((exp2 - bias) >= 0x07FF) { // (1 << 11) - 1.
+ goto infinity;
+ }
+ }
+
+ // Handle subnormal numbers.
+ if ((man2 >> 52) == 0) {
+ exp2 = bias;
+ }
+
+ // Pack the bits and return.
+ uint64_t exp2_bits = (uint64_t)((exp2 - bias) & 0x07FF); // (1 << 11) - 1.
+ uint64_t bits = (man2 & 0x000FFFFFFFFFFFFF) | // (1 << 52) - 1.
+ (exp2_bits << 52) | //
+ (h.negative ? 0x8000000000000000 : 0); // (1 << 63).
+
+ wuffs_base__result_f64 ret;
+ ret.status.repr = NULL;
+ ret.value = wuffs_base__ieee_754_bit_representation__to_f64(bits);
+ return ret;
+ } while (0);
+
+zero:
+ do {
+ uint64_t bits = h.negative ? 0x8000000000000000 : 0;
+
+ wuffs_base__result_f64 ret;
+ ret.status.repr = NULL;
+ ret.value = wuffs_base__ieee_754_bit_representation__to_f64(bits);
+ return ret;
+ } while (0);
+
+infinity:
+ do {
+ uint64_t bits = h.negative ? 0xFFF0000000000000 : 0x7FF0000000000000;
+
+ wuffs_base__result_f64 ret;
+ ret.status.repr = NULL;
+ ret.value = wuffs_base__ieee_754_bit_representation__to_f64(bits);
+ return ret;
+ } while (0);
+}
+
// ---------------- Unicode and UTF-8
size_t //
diff --git a/script/print-hpd-left-shift.go b/script/print-hpd-left-shift.go
new file mode 100644
index 0000000..47141bd
--- /dev/null
+++ b/script/print-hpd-left-shift.go
@@ -0,0 +1,114 @@
+// 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-hpd-left-shift.go prints the
+// wuffs_base__private_implementation__high_prec_dec__lshift_num_new_digits
+// tables.
+//
+// Usage: go run print-hpd-left-shift.go -comments
+
+import (
+ "flag"
+ "fmt"
+ "math"
+ "math/big"
+)
+
+var (
+ comments = flag.Bool("comments", false, "whether to print comments")
+)
+
+// powerOf5 return "5 ** n" as a string.
+func powerOf5(n int64) string {
+ x := big.NewInt(5)
+ x.Exp(x, big.NewInt(n), nil)
+ return x.String()
+}
+
+func ellipsize(s string) string {
+ if len(s) <= 16 {
+ return s
+ }
+ return s[:8] + "..." + s[len(s)-5:]
+}
+
+func main() {
+ flag.Parse()
+
+ const WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__SHIFT__MAX_INCL = 60
+ const log2log10 = math.Ln2 / math.Ln10
+ data := []byte(nil)
+
+ fmt.Printf("static const uint16_t " +
+ "wuffs_base__private_implementation__hpd_left_shift[65] = {\n")
+ fmt.Printf(" 0x0000,")
+ if *comments {
+ fmt.Printf("// i= 0\n")
+ }
+ for i := int64(1); i <= WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__SHIFT__MAX_INCL; i++ {
+ offset := int64(len(data))
+ if offset > 0x07FF {
+ panic("offset requires more than 11 bits")
+ }
+ numNewDigits := int64(log2log10*float64(i)) + 1
+ if numNewDigits > 31 {
+ panic("numNewDigits requires more than 5 bits")
+ }
+ code := (numNewDigits << 11) | offset
+
+ p := powerOf5(i)
+ data = append(data, p...)
+ fmt.Printf(" 0x%04X,", code)
+ if *comments {
+ fmt.Printf(" // i=%2d, num_new_digits=%2d, offset=0x%04X, 5**i=%s\n",
+ i, numNewDigits, offset, ellipsize(p))
+ } else if i&3 == 3 {
+ fmt.Println()
+ }
+ }
+ for i := 1 + WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__SHIFT__MAX_INCL; i < 65; i++ {
+ fmt.Printf(" 0x%04X,", len(data))
+ if *comments {
+ fmt.Printf(" // i=%2d\n", i)
+ }
+ }
+ fmt.Printf("};\n\n")
+ if len(data) > 0x07FF {
+ panic("offset requires more than 11 bits")
+ }
+
+ fmt.Printf("static const uint8_t "+
+ "wuffs_base__private_implementation__powers_of_5[0x%04X] = {\n", len(data))
+ for i, x := range data {
+ if (i & 15) == 0 {
+ fmt.Printf(" ")
+ }
+ fmt.Printf("%d, ", x&0x0F)
+ if (i & 15) == 15 {
+ if *comments {
+ fmt.Printf(" // offset=0x%04X\n", i&^15)
+ } else {
+ fmt.Println()
+ }
+ }
+ }
+ if *comments {
+ fmt.Printf(" // offset=0x%04X\n", len(data)&^15)
+ }
+ fmt.Printf("};\n")
+}
diff --git a/test/c/std/json.c b/test/c/std/json.c
index 3004565..eb9632a 100644
--- a/test/c/std/json.c
+++ b/test/c/std/json.c
@@ -69,6 +69,401 @@
// ---------------- String Conversions Tests
+// wuffs_base__private_implementation__high_prec_dec__to_debug_string converts
+// hpd into a human-readable NUL-terminated C string.
+const char* //
+wuffs_base__private_implementation__high_prec_dec__to_debug_string(
+ wuffs_base__private_implementation__high_prec_dec* hpd,
+ wuffs_base__slice_u8 dst) {
+ if (!hpd) {
+ return "high_prec_dec__to_debug_string: invalid hpd";
+ }
+ uint8_t* p = dst.ptr;
+ uint8_t* q = dst.ptr + dst.len;
+
+ // Sign bit.
+ if ((q - p) < 1) {
+ goto too_short;
+ }
+ *p++ = hpd->negative ? '-' : '+';
+
+ // Digits and decimal point.
+ if (hpd->decimal_point >
+ +WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DECIMAL_POINT__RANGE) {
+ // We have "infinity".
+ if ((q - p) < 3) {
+ goto too_short;
+ }
+ *p++ = 'i';
+ *p++ = 'n';
+ *p++ = 'f';
+ goto nul_terminator;
+
+ } else if (hpd->decimal_point <
+ -WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DECIMAL_POINT__RANGE) {
+ // We have "epsilon": a very small number, equivalent to zero.
+ if ((q - p) < 3) {
+ goto too_short;
+ }
+ *p++ = 'e';
+ *p++ = 'p';
+ *p++ = 's';
+ goto nul_terminator;
+
+ } else if (hpd->num_digits == 0) {
+ // We have "0".
+ if ((q - p) < 1) {
+ goto too_short;
+ }
+ *p++ = '0';
+ goto nul_terminator;
+
+ } else if (hpd->decimal_point < 0) {
+ // Referring to the wuffs_base__private_implementation__high_prec_dec
+ // typedef's comment, we have something like ".00789".
+ if ((q - p) < (hpd->num_digits + ((uint32_t)(-hpd->decimal_point)) + 1)) {
+ goto too_short;
+ }
+ uint8_t* src = &hpd->digits[0];
+
+ // Step A.1: write the ".".
+ *p++ = '.';
+
+ // Step A.2: write the "00".
+ uint32_t n = ((uint32_t)(-hpd->decimal_point));
+ if (n > 0) {
+ memset(p, '0', n);
+ p += n;
+ }
+
+ // Step A.3: write the "789".
+ n = hpd->num_digits;
+ while (n--) {
+ *p++ = '0' | *src++;
+ }
+
+ } else if (((uint32_t)(hpd->decimal_point)) <= hpd->num_digits) {
+ // Referring to the wuffs_base__private_implementation__high_prec_dec
+ // typedef's comment, we have something like "78.9".
+ if ((q - p) < (hpd->num_digits + 1)) {
+ goto too_short;
+ }
+ uint8_t* src = &hpd->digits[0];
+
+ // Step B.1: write the "78".
+ uint32_t n = ((uint32_t)(hpd->decimal_point));
+ while (n--) {
+ *p++ = '0' | *src++;
+ }
+
+ // Step B.2: write the ".".
+ *p++ = '.';
+
+ // Step B.3: write the "9".
+ n = hpd->num_digits - ((uint32_t)(hpd->decimal_point));
+ while (n--) {
+ *p++ = '0' | *src++;
+ }
+
+ } else {
+ // Referring to the wuffs_base__private_implementation__high_prec_dec
+ // typedef's comment, we have something like "78900.".
+ if ((q - p) < (((uint32_t)(hpd->decimal_point)) + 1)) {
+ goto too_short;
+ }
+ uint8_t* src = &hpd->digits[0];
+
+ // Step C.1: write the "789".
+ uint32_t n = hpd->num_digits;
+ while (n--) {
+ *p++ = '0' | *src++;
+ }
+
+ // Step C.2: write the "00".
+ n = ((uint32_t)(hpd->decimal_point)) - hpd->num_digits;
+ if (n > 0) {
+ memset(p, '0', n);
+ p += n;
+ }
+
+ // Step C.3: write the ".".
+ *p++ = '.';
+ }
+
+ // Truncated bit.
+ if (hpd->truncated) {
+ if ((q - p) < 1) {
+ goto too_short;
+ }
+ *p++ = '$';
+ }
+
+nul_terminator:
+ if ((q - p) < 1) {
+ goto too_short;
+ }
+ *p++ = '\x00';
+ return NULL;
+
+too_short:
+ return "high_prec_dec__to_debug_string: dst buffer is too short";
+}
+
+const char* //
+test_strconv_hpd_rounded_integer() {
+ CHECK_FOCUS(__func__);
+
+ struct {
+ uint64_t want;
+ const char* str;
+ } test_cases[] = {
+ {.want = 4, .str = "-3.9"}, //
+ {.want = 3, .str = "-3.14159"}, //
+ {.want = 0, .str = "+0"}, //
+ {.want = 0, .str = "0.0000000009"}, //
+ {.want = 0, .str = "0.1"}, //
+ {.want = 1, .str = "0.9"}, //
+ {.want = 12, .str = "1234e-2"}, //
+ {.want = 57, .str = "5678e-2"}, //
+ {.want = 60, .str = "60.0"}, //
+ {.want = 60, .str = "60.4999"}, //
+ {.want = 60, .str = "60.5"}, //
+ {.want = 60, .str = "60.5000"}, //
+ {.want = 61, .str = "60.5001"}, //
+ {.want = 61, .str = "60.6"}, //
+ {.want = 61, .str = "61.0"}, //
+ {.want = 61, .str = "61.4999"}, //
+ {.want = 62, .str = "61.5"}, //
+ {.want = 62, .str = "61.5000"}, //
+ {.want = 62, .str = "61.5001"}, //
+ {.want = 62, .str = "61.6"}, //
+ {.want = 62, .str = "62.0"}, //
+ {.want = 62, .str = "62.4999"}, //
+ {.want = 62, .str = "62.5"}, //
+ {.want = 62, .str = "62.5000"}, //
+ {.want = 63, .str = "62.5001"}, //
+ {.want = 63, .str = "62.6"}, //
+ {.want = 1000, .str = "999.999"}, //
+ {.want = 4560000, .str = "456e+4"}, //
+
+ // With round-to-even, ½ rounds to 0 but "a tiny bit more than ½" rounds
+ // to 1, even if the HPD struct truncates that "1" digit.
+ {.want = 0, .str = "0.5"}, //
+ {.want = 1, // 50 '0's per row.
+ .str = "0.500000000000000000000000000000000000000000000000"
+ "00000000000000000000000000000000000000000000000000"
+ "00000000000000000000000000000000000000000000000000"
+ "00000000000000000000000000000000000000000000000000"
+ "00000000000000000000000000000000000000000000000000"
+ "00000000000000000000000000000000000000000000000000"
+ "00000000000000000000000000000000000000000000000000"
+ "00000000000000000000000000000000000000000000000000"
+ "00000000000000000000000000000000000000000000000000"
+ "00000000000000000000000000000000000000000000000000"
+ "00000000000000000000000000000000000000000000000000"
+ "00000000000000000000000000000000000000000000000000"
+ "00000000000000000000000000000000000000000000000001"}, //
+
+ // Inputs with exactly 18 decimal digits before the decimal point.
+ {.want = 123456789012345679, .str = "123456789012345678.9"}, //
+ {.want = 1000000000000000000, .str = "999999999999999999.9"}, //
+
+ // Inputs with exactly 19 decimal digits before the decimal point.
+ {.want = UINT64_MAX, .str = "1234567890123456789"}, //
+ };
+
+ int tc;
+ for (tc = 0; tc < WUFFS_TESTLIB_ARRAY_SIZE(test_cases); tc++) {
+ wuffs_base__private_implementation__high_prec_dec hpd;
+ CHECK_STATUS(
+ "hpd__parse",
+ wuffs_base__private_implementation__high_prec_dec__parse(
+ &hpd, wuffs_base__make_slice_u8((void*)test_cases[tc].str,
+ strlen(test_cases[tc].str))));
+ uint64_t have =
+ wuffs_base__private_implementation__high_prec_dec__rounded_integer(
+ &hpd);
+ if (have != test_cases[tc].want) {
+ RETURN_FAIL("\"%s\": have %" PRIu64 ", want %" PRIu64, test_cases[tc].str,
+ have, test_cases[tc].want);
+ }
+ }
+ return NULL;
+}
+
+const char* //
+test_strconv_hpd_shift() {
+ CHECK_FOCUS(__func__);
+
+ struct {
+ const char* str;
+ int32_t shift; // -ve means left shift, +ve means right shift.
+ const char* want;
+ } test_cases[] = {
+ {.str = "0", .shift = +2, .want = "+0"}, //
+ {.str = "1", .shift = +3, .want = "+.125"}, //
+ {.str = "12e3", .shift = +5, .want = "+375."}, //
+ {.str = "-0.007", .shift = +8, .want = "-.00002734375"}, //
+ {.str = "3.14159E+26",
+ .shift = +60,
+ .want = "+272489496.244698869986677891574800014495849609375"}, //
+
+ {.str = "0", .shift = -2, .want = "+0"}, //
+ {.str = ".125", .shift = -3, .want = "+1."}, //
+ {.str = "3750e-1", .shift = -5, .want = "+12000."}, //
+ {.str = "-2.734375e-5", .shift = -8, .want = "-.007"}, //
+ {.str = "+272489496.244698869986677891574800014495849609375",
+ .shift = -60,
+ .want = "+314159000000000000000000000."}, //
+ };
+
+ int tc;
+ for (tc = 0; tc < WUFFS_TESTLIB_ARRAY_SIZE(test_cases); tc++) {
+ wuffs_base__private_implementation__high_prec_dec hpd;
+ CHECK_STATUS(
+ "hpd__parse",
+ wuffs_base__private_implementation__high_prec_dec__parse(
+ &hpd, wuffs_base__make_slice_u8((void*)test_cases[tc].str,
+ strlen(test_cases[tc].str))));
+ int32_t shift = test_cases[tc].shift;
+ if (shift > 0) {
+ wuffs_base__private_implementation__high_prec_dec__small_rshift(
+ &hpd, (uint32_t)(+shift));
+ } else if (shift < 0) {
+ wuffs_base__private_implementation__high_prec_dec__small_lshift(
+ &hpd, (uint32_t)(-shift));
+ }
+
+ uint8_t have[1024];
+ CHECK_STRING(
+ wuffs_base__private_implementation__high_prec_dec__to_debug_string(
+ &hpd,
+ wuffs_base__make_slice_u8(have, WUFFS_TESTLIB_ARRAY_SIZE(have))));
+ if (strcmp(((void*)(have)), test_cases[tc].want)) {
+ RETURN_FAIL("\"%s\" %s %" PRId32 ":\n have: \"%s\"\n want: \"%s\"",
+ test_cases[tc].str, ((shift > 0) ? ">>" : "<<"),
+ ((shift > 0) ? +shift : -shift), have, test_cases[tc].want);
+ }
+ }
+ return NULL;
+}
+
+const char* //
+test_strconv_parse_number_f64() {
+ CHECK_FOCUS(__func__);
+
+ const uint64_t fail = 0xDEADBEEF;
+
+ struct {
+ uint64_t want;
+ const char* str;
+ } test_cases[] = {
+ {.want = 0x0000000000000000, .str = "+0.0"},
+ {.want = 0x0000000000000000, .str = "0"},
+ {.want = 0x0000000000000000, .str = "0e0"},
+ {.want = 0x0000000000000001, .str = "4.9406564584124654e-324"},
+ {.want = 0x000FFFFFFFFFFFFF, .str = "2.2250738585072009E-308"},
+ {.want = 0x0010000000000000, .str = "2.2250738585072014E-308"},
+ {.want = 0x3F88000000000000, .str = "0.01171875"},
+ {.want = 0x3FD0000000000000, .str = ".25"},
+ {.want = 0x3FD3333333333333,
+ .str = "0.2999999999999999888977697537484345957636833190917968750000"},
+ {.want = 0x3FD3333333333333, .str = "0.3"},
+ {.want = 0x3FD3333333333334, .str = "0.30000000000000004"},
+ {.want = 0x3FD3333333333334,
+ .str = "0.3000000000000000444089209850062616169452667236328125000000"},
+ {.want = 0x3FD5555555555555, .str = "0.333333333333333333333333333333"},
+ {.want = 0x3FEFFFFFFFFFFFFF, .str = "0.99999999999999988898"},
+ {.want = 0x3FF0000000000000, .str = "0.999999999999999999999999999999"},
+ {.want = 0x3FF0000000000000, .str = "1"},
+ {.want = 0x3FF0000000000001, .str = "1.0000000000000002"},
+ {.want = 0x3FF0000000000002, .str = "1.0000000000000004"},
+ {.want = 0x3FF4000000000000, .str = "1.25"},
+ {.want = 0x3FF8000000000000, .str = "+1.5"},
+ {.want = 0x4000000000000000, .str = "2"},
+ {.want = 0x400921FB54442D18, .str = "3.141592653589793238462643383279"},
+ {.want = 0x400C000000000000, .str = "3.5"},
+ {.want = 0x4014000000000000, .str = "5"},
+ {.want = 0x4036000000000000, .str = "22"},
+ {.want = 0x4036000000000000, .str = "_+__2_2__."},
+ {.want = 0x4037000000000000, .str = "23"},
+ {.want = 0x4038000000000000, .str = "2.4E+00000000001"},
+ {.want = 0x4038000000000000, .str = "2.4E001"},
+ {.want = 0x4038000000000000, .str = "2.4E1"},
+ {.want = 0x4038000000000000, .str = "24"},
+ {.want = 0x4038000000000000, .str = "2400_00000_00000.00000_e-_1_2"},
+ {.want = 0x40FE240C9FCB0C02, .str = "123456.789012"},
+ {.want = 0x4330000000000000, .str = "4503599627370496"}, // 1 << 52.
+ {.want = 0x4330000000000000, .str = "4503599627370496.5"},
+ {.want = 0x4330000000000001, .str = "4503599627370497"},
+ {.want = 0x4330000000000002, .str = "4503599627370497.5"},
+ {.want = 0x4330000000000002, .str = "4503599627370498"},
+ {.want = 0x4340000000000000, .str = "9007199254740992"}, // 1 << 53.
+ {.want = 0x4340000000000000, .str = "9007199254740993"},
+ {.want = 0x4340000000000001, .str = "9007199254740994"},
+ {.want = 0x4340000000000002, .str = "9007199254740995"},
+ {.want = 0x4340000000000002, .str = "9007199254740996"},
+ {.want = 0x4340000000000002, .str = "9_007__199_254__740_996"},
+ {.want = 0x54B249AD2594C37D, .str = "+1E+100"},
+ {.want = 0x54B249AD2594C37D, .str = "+_1_E_+_1_0_0_"},
+ {.want = 0x7FEFFFFFFFFFFFFF, .str = "1.7976931348623157e308"},
+ {.want = 0x7FF0000000000000, .str = "1.8e308"},
+ {.want = 0x7FF0000000000000, .str = "1e999"},
+ {.want = 0x7FF0000000000000, .str = "__InFinity__"},
+ {.want = 0x7FF0000000000000, .str = "inf"},
+ {.want = 0x7FFFFFFFFFFFFFFF, .str = "+nan"},
+ {.want = 0x7FFFFFFFFFFFFFFF, .str = "_+_NaN_"},
+ {.want = 0x7FFFFFFFFFFFFFFF, .str = "nan"},
+ {.want = 0x8000000000000000, .str = "-0.000e0"},
+ {.want = 0xC008000000000000, .str = "-3"},
+ {.want = 0xFFF0000000000000, .str = "-2e308"},
+ {.want = 0xFFF0000000000000, .str = "-inf"},
+ {.want = 0xFFFFFFFFFFFFFFFF, .str = "-NAN"},
+
+ // We accept either ',' or '.'.
+ {.want = 0x3FFC000000000000, .str = "1,75"},
+ {.want = 0x3FFC000000000000, .str = "1.75"},
+
+ {.want = fail, .str = " 0"},
+ {.want = fail, .str = ""},
+ {.want = fail, .str = "."},
+ {.want = fail, .str = "00"},
+ {.want = fail, .str = "001.2"},
+ {.want = fail, .str = "06.44"},
+ {.want = fail, .str = "0644"},
+ {.want = fail, .str = "1234 67.8e9"},
+ {.want = fail, .str = "2,345,678"}, // Two ','s.
+ {.want = fail, .str = "2.345,678"}, // One '.' and one ','.
+ {.want = fail, .str = "7 "},
+ {.want = fail, .str = "7 .9"},
+ {.want = fail, .str = "7e"},
+ {.want = fail, .str = "7e-"},
+ {.want = fail, .str = "7e-+1"},
+ {.want = fail, .str = "7e++1"},
+ {.want = fail, .str = "NAN "},
+ {.want = fail, .str = "NANA"},
+ {.want = fail, .str = "inf_inity"},
+ {.want = fail, .str = "nun"},
+ };
+
+ int tc;
+ for (tc = 0; tc < WUFFS_TESTLIB_ARRAY_SIZE(test_cases); tc++) {
+ wuffs_base__result_f64 r =
+ wuffs_base__parse_number_f64(wuffs_base__make_slice_u8(
+ (void*)test_cases[tc].str, strlen(test_cases[tc].str)));
+ uint64_t have =
+ (r.status.repr == NULL)
+ ? wuffs_base__ieee_754_bit_representation__from_f64(r.value)
+ : fail;
+ if (have != test_cases[tc].want) {
+ RETURN_FAIL("\"%s\": have 0x%" PRIX64 ", want 0x%" PRIX64,
+ test_cases[tc].str, have, test_cases[tc].want);
+ }
+ }
+
+ return NULL;
+}
+
const char* //
test_strconv_parse_number_i64() {
CHECK_FOCUS(__func__);
@@ -1033,9 +1428,12 @@
// These strconv tests are really testing the Wuffs base library. They
// aren't specific to the std/json code, but putting them here is as good
// as any other place.
- test_strconv_parse_number_i64, //
- test_strconv_parse_number_u64, //
- test_strconv_utf_8_next, //
+ test_strconv_hpd_rounded_integer, //
+ test_strconv_hpd_shift, //
+ test_strconv_parse_number_f64, //
+ test_strconv_parse_number_i64, //
+ test_strconv_parse_number_u64, //
+ test_strconv_utf_8_next, //
test_wuffs_json_decode_interface, //
test_wuffs_json_decode_long_numbers, //