Add PARSE_NUMBER_FXX__REJECT_INF_AND_NAN
diff --git a/internal/cgen/base/floatconv-submodule-code.c b/internal/cgen/base/floatconv-submodule-code.c
index b92eb54..5017453 100644
--- a/internal/cgen/base/floatconv-submodule-code.c
+++ b/internal/cgen/base/floatconv-submodule-code.c
@@ -977,15 +977,19 @@
static wuffs_base__result_f64 //
wuffs_base__private_implementation__parse_number_f64_special(
wuffs_base__slice_u8 s,
- const char* fallback_status_repr) {
+ uint32_t options) {
do {
+ if (options & WUFFS_BASE__PARSE_NUMBER_FXX__REJECT_INF_AND_NAN) {
+ goto fail;
+ }
+
uint8_t* p = s.ptr;
uint8_t* q = s.ptr + s.len;
for (; (p < q) && (*p == '_'); p++) {
}
if (p >= q) {
- goto fallback;
+ goto fail;
}
// Parse sign.
@@ -1003,7 +1007,7 @@
}
} while (0);
if (p >= q) {
- goto fallback;
+ goto fail;
}
bool nan = false;
@@ -1013,7 +1017,7 @@
if (((q - p) < 3) || //
((p[1] != 'N') && (p[1] != 'n')) || //
((p[2] != 'F') && (p[2] != 'f'))) {
- goto fallback;
+ goto fail;
}
p += 3;
@@ -1025,21 +1029,21 @@
((p[2] != 'I') && (p[2] != 'i')) || //
((p[3] != 'T') && (p[3] != 't')) || //
((p[4] != 'Y') && (p[4] != 'y'))) {
- goto fallback;
+ goto fail;
}
p += 5;
if ((p >= q) || (*p == '_')) {
break;
}
- goto fallback;
+ goto fail;
case 'N':
case 'n':
if (((q - p) < 3) || //
((p[1] != 'A') && (p[1] != 'a')) || //
((p[2] != 'N') && (p[2] != 'n'))) {
- goto fallback;
+ goto fail;
}
p += 3;
@@ -1047,17 +1051,17 @@
nan = true;
break;
}
- goto fallback;
+ goto fail;
default:
- goto fallback;
+ goto fail;
}
// Finish.
for (; (p < q) && (*p == '_'); p++) {
}
if (p != q) {
- goto fallback;
+ goto fail;
}
wuffs_base__result_f64 ret;
ret.status.repr = NULL;
@@ -1067,10 +1071,10 @@
return ret;
} while (0);
-fallback:
+fail:
do {
wuffs_base__result_f64 ret;
- ret.status.repr = fallback_status_repr;
+ ret.status.repr = wuffs_base__error__bad_argument;
ret.value = 0;
return ret;
} while (0);
@@ -1078,7 +1082,8 @@
WUFFS_BASE__MAYBE_STATIC wuffs_base__result_f64 //
wuffs_base__private_implementation__high_prec_dec__to_f64(
- wuffs_base__private_implementation__high_prec_dec* h) {
+ wuffs_base__private_implementation__high_prec_dec* h,
+ uint32_t options) {
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
@@ -1226,6 +1231,13 @@
infinity:
do {
+ if (options & WUFFS_BASE__PARSE_NUMBER_FXX__REJECT_INF_AND_NAN) {
+ wuffs_base__result_f64 ret;
+ ret.status.repr = wuffs_base__error__bad_argument;
+ ret.value = 0;
+ return ret;
+ }
+
uint64_t bits = h->negative ? 0xFFF0000000000000 : 0x7FF0000000000000;
wuffs_base__result_f64 ret;
@@ -1459,9 +1471,10 @@
options);
if (status.repr) {
return wuffs_base__private_implementation__parse_number_f64_special(
- s, status.repr);
+ s, options);
}
- return wuffs_base__private_implementation__high_prec_dec__to_f64(&h);
+ return wuffs_base__private_implementation__high_prec_dec__to_f64(&h,
+ options);
} while (0);
}
diff --git a/internal/cgen/data/data.go b/internal/cgen/data/data.go
index 70b5a8a..b6311ba 100644
--- a/internal/cgen/data/data.go
+++ b/internal/cgen/data/data.go
@@ -70,23 +70,23 @@
"o \"73 or 74,\n // depending on msb\", but a flat \"73\" is simpler.\n if ((x_lo == 0) && ((x_hi & 0x1FF) == 0) && ((ret_mantissa & 3) == 1)) {\n return -1;\n }\n\n // If we're not halfway then it's rounding to-nearest. Starting with a 54-bit\n // number, carry the lowest bit (bit 0) up if it's on. Regardless of whether\n // it was on or off, shifting right by one then produces a 53-bit number. If\n // carrying up overflowed, shift again.\n ret_mantissa += ret_mantissa & 1;\n ret_mantissa >>= 1;\n if ((ret_mantissa >> 53) > 0) {\n ret_mantissa >>= 1;\n ret_exp2++;\n }\n\n // Starting with a 53-bit number, IEEE 754 double-precision normal numbers\n // have an implicit mantissa bit. Mask that away and keep the low 52 bits.\n ret_mantissa &= 0x000FFFFFFFFFFFFF;\n\n // IEEE 754 double-precision floating point has 11 exponent bits. All off (0)\n // means subnormal numbers. All on (2047) means infinity or NaN.\n if ((ret_exp2 <= 0) || (2047 <= ret_exp2)) {\n return -1;\n }\n\n // Pack the bits and return.\n return " +
"((int64_t)(ret_mantissa | (ret_exp2 << 52)));\n}\n\n" +
"" +
- "// --------\n\nstatic wuffs_base__result_f64 //\nwuffs_base__private_implementation__parse_number_f64_special(\n 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 " +
- "= wuffs_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__MAYBE_STATIC wuffs_base__result_f64 //\nwuffs_base__private_implementation__high_prec_dec__to_f64(\n wuffs_base__private_implementation__high_prec_dec* h) {\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 // 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 // Try the fast Eisel algorithm again. Calculating the (man, exp10) pair\n // from the high_prec_dec h is more correct but slower than the approach\n // taken in wuffs_base__parse_number_f64. The latter is optimized for the\n // common cases (e.g. assuming no underscores or a leading '+' sign) rather\n // than the full set of cases allowed by the Wuffs API.\n if (h->num_digits <= 19) {\n uint64_t man = 0;\n uint32_t i;\n for (i = 0; i < h->num_digits; i++) {\n man = (10 * man) + h->digits[i];\n }\n int32_t exp10 = h->decimal_point - ((int32_t)(h->num_digits));\n if ((man != 0) && (-326 <= exp10) && (exp10 <= 310)) {\n int64_t r = wuffs_base__private_implementation__parse_number_f64_eisel(\n man, exp10);\n if (r >= 0) {\n wuffs_base__result_f64 " +
- "ret;\n ret.status.repr = NULL;\n ret.value = wuffs_base__ieee_754_bit_representation__to_f64(\n ((uint64_t)r) | (((uint64_t)(h->negative)) << 63));\n return ret;\n }\n }\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 f64_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, shift);\n if (h->decimal_point <\n -WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DECIMAL_POINT__RANGE) {\n goto zero;\n }\n exp2 += (int32_t)shift;\n }\n // ...then we shift lef" +
- "t, 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, shift);\n if (h->decimal_point >\n +WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DECIMAL_POINT__RANGE) {\n goto infinity;\n }\n exp2 -= (int32_t)shift;\n }\n\n // We're in the range [½ .. 1] but f64 uses [1 .. 2].\n exp2--;\n\n // The minimum normal exponent is (f64_bias + 1).\n while ((f64_bias + 1) > exp2) {\n uint32_t n = (uint32_t)((f64_bias + 1) - exp2);\n if (n > WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__SHIFT__MAX_INCL) {\n n = WUFFS_BASE__PRIVATE_I" +
- "MPLEMENTATION__HPD__SHIFT__MAX_INCL;\n }\n wuffs_base__private_implementation__high_prec_dec__small_rshift(h, n);\n exp2 += (int32_t)n;\n }\n\n // Check for overflow.\n if ((exp2 - f64_bias) >= 0x07FF) { // (1 << 11) - 1.\n goto infinity;\n }\n\n // Extract 53 bits for the mantissa (in base-2).\n wuffs_base__private_implementation__high_prec_dec__small_lshift(h, 53);\n uint64_t man2 =\n wuffs_base__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 - f64_bias) >= 0x07FF) { // (1 << 11) - 1.\n goto infinity;\n }\n }\n\n // Handle subnormal numbers.\n if ((man2 >> 52) == 0) {\n exp2 = f64_bias;\n }\n\n // Pack the bits and return.\n uint64_t exp2_bits =\n (uint64_t)((exp2 - f64_bias) & 0x07FF); // (1 << 11) - 1.\n uint64_t bits = (man2 & 0x000FFFFFFFFFFFFF) | " +
- "// (1 << 52) - 1.\n (exp2_bits << 52) | //\n (h->negative ? 0x8000000000000000 : 0); // (1 << 63).\n\n wuffs_base__result_f64 ret;\n ret.status.repr = NULL;\n ret.value = wuffs_base__ieee_754_bit_representation__to_f64(bits);\n return ret;\n } while (0);\n\nzero:\n do {\n uint64_t bits = h->negative ? 0x8000000000000000 : 0;\n\n wuffs_base__result_f64 ret;\n ret.status.repr = NULL;\n ret.value = wuffs_base__ieee_754_bit_representation__to_f64(bits);\n return ret;\n } while (0);\n\ninfinity:\n do {\n uint64_t bits = h->negative ? 0xFFF0000000000000 : 0x7FF0000000000000;\n\n wuffs_base__result_f64 ret;\n ret.status.repr = NULL;\n ret.value = wuffs_base__ieee_754_bit_representation__to_f64(bits);\n return ret;\n } while (0);\n}\n\nstatic inline bool //\nwuffs_base__private_implementation__is_decimal_digit(uint8_t c) {\n return ('0' <= c) && (c <= '9');\n}\n\nWUFFS_BASE__MAYBE_STATIC wuffs_base__result_f64 //\nwuffs_base__parse_number_f64(wu" +
- "ffs_base__slice_u8 s, uint32_t options) {\n // In practice, almost all \"dd.ddddE±xxx\" numbers can be represented\n // losslessly by a uint64_t mantissa \"dddddd\" and an int32_t base-10\n // exponent, adjusting \"xxx\" for the position (if present) of the decimal\n // separator '.' or ','.\n //\n // This (u64 man, i32 exp10) data structure is superficially similar to the\n // \"Do It Yourself Floating Point\" type from Loitsch (†), but the exponent\n // here is base-10, not base-2.\n //\n // If s's number fits in a (man, exp10), parse that pair with the Eisel\n // algorithm. If not, or if Eisel fails, parsing s with the fallback\n // algorithm is slower but comprehensive.\n //\n // † \"Printing Floating-Point Numbers Quickly and Accurately with Integers\"\n // (https://www.cs.tufts.edu/~nr/cs257/archive/florian-loitsch/printf.pdf).\n // Florian Loitsch is also the primary contributor to\n // https://github.com/google/double-conversion\n do {\n // Calculating that (man, exp10) pair needs to stay within s's boun" +
- "ds.\n // Provided that s isn't extremely long, work on a NUL-terminated copy of\n // s's contents. The NUL byte isn't a valid part of \"±dd.ddddE±xxx\".\n //\n // As the pointer p walks the contents, it's faster to repeatedly check \"is\n // *p a valid digit\" than \"is p within bounds and *p a valid digit\".\n if (s.len >= 256) {\n goto fallback;\n }\n uint8_t z[256];\n memcpy(&z[0], s.ptr, s.len);\n z[s.len] = 0;\n const uint8_t* p = &z[0];\n\n // Look for a leading minus sign. Technically, we could also look for an\n // optional plus sign, but the \"script/process-json-numbers.c with -p\"\n // benchmark is noticably slower if we do. It's optional and, in practice,\n // usually absent. Let the fallback catch it.\n bool negative = (*p == '-');\n if (negative) {\n p++;\n }\n\n // After walking \"dd.dddd\", comparing p later with p now will produce the\n // number of \"d\"s and \".\"s.\n const uint8_t* const start_of_digits_ptr = p;\n\n // Walk the \"d\"s before a '.', 'E', N" +
- "UL byte, etc. If it starts with '0',\n // it must be a single '0'. If it starts with a non-zero decimal digit, it\n // can be a sequence of decimal digits.\n //\n // Update the man variable during the walk. It's OK if man overflows now.\n // We'll detect that later.\n uint64_t man;\n if (*p == '0') {\n man = 0;\n p++;\n if (wuffs_base__private_implementation__is_decimal_digit(*p)) {\n goto fallback;\n }\n } else if (wuffs_base__private_implementation__is_decimal_digit(*p)) {\n man = ((uint8_t)(*p - '0'));\n p++;\n for (; wuffs_base__private_implementation__is_decimal_digit(*p); p++) {\n man = (10 * man) + ((uint8_t)(*p - '0'));\n }\n } else {\n goto fallback;\n }\n\n // Walk the \"d\"s after the optional decimal separator ('.' or ','),\n // updating the man and exp10 variables.\n int32_t exp10 = 0;\n if (*p ==\n ((options & WUFFS_BASE__PARSE_NUMBER_FXX__DECIMAL_SEPARATOR_IS_A_COMMA)\n ? ','\n : '.')) {\n p" +
- "++;\n const uint8_t* first_after_separator_ptr = p;\n if (!wuffs_base__private_implementation__is_decimal_digit(*p)) {\n goto fallback;\n }\n man = (10 * man) + ((uint8_t)(*p - '0'));\n p++;\n for (; wuffs_base__private_implementation__is_decimal_digit(*p); p++) {\n man = (10 * man) + ((uint8_t)(*p - '0'));\n }\n exp10 = ((int32_t)(first_after_separator_ptr - p));\n }\n\n // Count the number of digits:\n // - for an input of \"314159\", digit_count is 6.\n // - for an input of \"3.14159\", digit_count is 7.\n //\n // This is off-by-one if there is a decimal separator. That's OK for now.\n // We'll correct for that later. The \"script/process-json-numbers.c with\n // -p\" benchmark is noticably slower if we try to correct for that now.\n uint32_t digit_count = (uint32_t)(p - start_of_digits_ptr);\n\n // Update exp10 for the optional exponent, starting with 'E' or 'e'.\n if ((*p | 0x20) == 'e') {\n p++;\n int32_t exp_sign = +1;\n if (*p ==" +
- " '-') {\n p++;\n exp_sign = -1;\n } else if (*p == '+') {\n p++;\n }\n if (!wuffs_base__private_implementation__is_decimal_digit(*p)) {\n goto fallback;\n }\n int32_t exp_num = ((uint8_t)(*p - '0'));\n p++;\n // The rest of the exp_num walking has a peculiar control flow but, once\n // again, the \"script/process-json-numbers.c with -p\" benchmark is\n // sensitive to alternative formulations.\n if (wuffs_base__private_implementation__is_decimal_digit(*p)) {\n exp_num = (10 * exp_num) + ((uint8_t)(*p - '0'));\n p++;\n }\n if (wuffs_base__private_implementation__is_decimal_digit(*p)) {\n exp_num = (10 * exp_num) + ((uint8_t)(*p - '0'));\n p++;\n }\n while (wuffs_base__private_implementation__is_decimal_digit(*p)) {\n if (exp_num > 0x1000000) {\n goto fallback;\n }\n exp_num = (10 * exp_num) + ((uint8_t)(*p - '0'));\n p++;\n }\n exp10 += exp_sign * exp_num;\n }\n\n // " +
- "The Wuffs API is that the original slice has no trailing data. It also\n // allows underscores, which we don't catch here but the fallback should.\n if (p != &z[s.len]) {\n goto fallback;\n }\n\n // Check that the uint64_t typed man variable has not overflowed, based on\n // digit_count.\n //\n // For reference:\n // - (1 << 63) is 9223372036854775808, which has 19 decimal digits.\n // - (1 << 64) is 18446744073709551616, which has 20 decimal digits.\n // - 19 nines, 9999999999999999999, is 0x8AC7230489E7FFFF, which has 64\n // bits and 16 hexadecimal digits.\n // - 20 nines, 99999999999999999999, is 0x56BC75E2D630FFFFF, which has 67\n // bits and 17 hexadecimal digits.\n if (digit_count > 19) {\n // Even if we have more than 19 pseudo-digits, it's not yet definitely an\n // overflow. Recall that digit_count might be off-by-one (too large) if\n // there's a decimal separator. It will also over-report the number of\n // meaningful digits if the " +
- "input looks something like \"0.000dddExxx\".\n //\n // We adjust by the number of leading '0's and '.'s and re-compare to 19.\n // Once again, technically, we could skip ','s too, but that perturbs the\n // \"script/process-json-numbers.c with -p\" benchmark.\n const uint8_t* q = start_of_digits_ptr;\n for (; (*q == '0') || (*q == '.'); q++) {\n }\n digit_count -= (uint32_t)(q - start_of_digits_ptr);\n if (digit_count > 19) {\n goto fallback;\n }\n }\n\n // The wuffs_base__private_implementation__parse_number_f64_eisel\n // preconditions include that exp10 is in the range -326 ..= 310.\n if ((exp10 < -326) || (310 < exp10)) {\n goto fallback;\n }\n\n // If man and exp10 are small enough, all three of (man), (10 ** exp10) and\n // (man ** (10 ** exp10)) are exactly representable by a double. We don't\n // need to run the Eisel algorithm.\n if ((-22 <= exp10) && (exp10 <= 22) && ((man >> 53) == 0)) {\n double d = (double)man;\n if (exp10 >= 0" +
- ") {\n d *= wuffs_base__private_implementation__f64_powers_of_10[+exp10];\n } else {\n d /= wuffs_base__private_implementation__f64_powers_of_10[-exp10];\n }\n wuffs_base__result_f64 ret;\n ret.status.repr = NULL;\n ret.value = negative ? -d : +d;\n return ret;\n }\n\n // The wuffs_base__private_implementation__parse_number_f64_eisel\n // preconditions include that man is non-zero. Parsing \"0\" should be caught\n // by the \"If man and exp10 are small enough\" above, but \"0e99\" might not.\n if (man == 0) {\n goto fallback;\n }\n\n // Our man and exp10 are in range. Run the Eisel algorithm.\n int64_t r =\n wuffs_base__private_implementation__parse_number_f64_eisel(man, exp10);\n if (r < 0) {\n goto fallback;\n }\n wuffs_base__result_f64 ret;\n ret.status.repr = NULL;\n ret.value = wuffs_base__ieee_754_bit_representation__to_f64(\n ((uint64_t)r) | (((uint64_t)negative) << 63));\n return ret;\n } while (0);\n\nfallback:\n do {\n wuffs_" +
- "base__private_implementation__high_prec_dec h;\n wuffs_base__status status =\n wuffs_base__private_implementation__high_prec_dec__parse(&h, s,\n options);\n if (status.repr) {\n return wuffs_base__private_implementation__parse_number_f64_special(\n s, status.repr);\n }\n return wuffs_base__private_implementation__high_prec_dec__to_f64(&h);\n } while (0);\n}\n\n" +
+ "// --------\n\nstatic wuffs_base__result_f64 //\nwuffs_base__private_implementation__parse_number_f64_special(\n wuffs_base__slice_u8 s,\n uint32_t options) {\n do {\n if (options & WUFFS_BASE__PARSE_NUMBER_FXX__REJECT_INF_AND_NAN) {\n goto fail;\n }\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 goto fail;\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 fail;\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 fail;\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 fail;\n }\n p += 5;\n\n if ((p >= q) || (*p == '_')) {\n break;\n }\n goto fail;\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 fail;\n }\n p += 3;\n\n if ((p >= q) || (*p == '_')) {\n nan = true;\n break;\n }\n goto fail;\n\n default:\n goto fail;\n }\n\n // Finish.\n for (; (p < q) && (*p == '_'); p++) {\n }\n if (p != q) {\n goto fail;\n }\n wuffs_base__result_f64 ret;\n" +
+ " ret.status.repr = NULL;\n ret.value = wuffs_base__ieee_754_bit_representation__to_f64(\n (nan ? 0x7FFFFFFFFFFFFFFF : 0x7FF0000000000000) |\n (negative ? 0x8000000000000000 : 0));\n return ret;\n } while (0);\n\nfail:\n do {\n wuffs_base__result_f64 ret;\n ret.status.repr = wuffs_base__error__bad_argument;\n ret.value = 0;\n return ret;\n } while (0);\n}\n\nWUFFS_BASE__MAYBE_STATIC wuffs_base__result_f64 //\nwuffs_base__private_implementation__high_prec_dec__to_f64(\n wuffs_base__private_implementation__high_prec_dec* h,\n uint32_t options) {\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 // Handle zero an" +
+ "d 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 // Try the fast Eisel algorithm again. Calculating the (man, exp10) pair\n // from the high_prec_dec h is more correct but slower than the approach\n // taken in wuffs_base__parse_number_f64. The latter is optimized for the\n // common cases (e.g. assuming no underscores or a leading '+' sign) rather\n // than the full set of cases allowed by the Wuffs API.\n if (h->num_digits <= 19) {\n uint64_t man = 0;\n uint32_t i;\n for (i = 0; i < h->num_digits; i++) {\n man = (10 * man) + h->digits[i];\n }\n int32_t exp10 = h->decimal_point - ((int32_t)(h->num_digits));\n if ((man != 0) && (-326 <= exp10) && (exp10 <= 310)) {\n int64_t r = wuffs_base__private_implementation__parse_number_f64_eisel(\n " +
+ " man, exp10);\n if (r >= 0) {\n wuffs_base__result_f64 ret;\n ret.status.repr = NULL;\n ret.value = wuffs_base__ieee_754_bit_representation__to_f64(\n ((uint64_t)r) | (((uint64_t)(h->negative)) << 63));\n return ret;\n }\n }\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 f64_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, shift);\n if (h->decimal_point <\n -WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DECIMAL_POINT__RANGE) {\n goto zero;\n" +
+ " }\n exp2 += (int32_t)shift;\n }\n // ...then we shift left, putting us in [½ .. 1].\n while (h->decimal_point <= 0) {\n uint32_t shift;\n if (h->decimal_point == 0) {\n if (h->digits[0] >= 5) {\n break;\n }\n shift = (h->digits[0] <= 2) ? 2 : 1;\n } else {\n uint32_t n = (uint32_t)(-h->decimal_point);\n shift = (n < num_powers)\n ? powers[n]\n : WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__SHIFT__MAX_INCL;\n }\n\n wuffs_base__private_implementation__high_prec_dec__small_lshift(h, shift);\n if (h->decimal_point >\n +WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__DECIMAL_POINT__RANGE) {\n goto infinity;\n }\n exp2 -= (int32_t)shift;\n }\n\n // We're in the range [½ .. 1] but f64 uses [1 .. 2].\n exp2--;\n\n // The minimum normal exponent is (f64_bias + 1).\n while ((f64_bias + 1) > exp2) {\n uint32_t n = (uint32_t)((f64_bias + 1) - exp2);\n if (n > WUFFS_BASE__PRIVATE_IM" +
+ "PLEMENTATION__HPD__SHIFT__MAX_INCL) {\n n = WUFFS_BASE__PRIVATE_IMPLEMENTATION__HPD__SHIFT__MAX_INCL;\n }\n wuffs_base__private_implementation__high_prec_dec__small_rshift(h, n);\n exp2 += (int32_t)n;\n }\n\n // Check for overflow.\n if ((exp2 - f64_bias) >= 0x07FF) { // (1 << 11) - 1.\n goto infinity;\n }\n\n // Extract 53 bits for the mantissa (in base-2).\n wuffs_base__private_implementation__high_prec_dec__small_lshift(h, 53);\n uint64_t man2 =\n wuffs_base__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 - f64_bias) >= 0x07FF) { // (1 << 11) - 1.\n goto infinity;\n }\n }\n\n // Handle subnormal numbers.\n if ((man2 >> 52) == 0) {\n exp2 = f64_bias;\n }\n\n // Pack the bits and return.\n uint64_t exp2_bits =\n (uint64_t)((exp2 - f64_bias) & 0x07FF); // (1 <<" +
+ " 11) - 1.\n uint64_t bits = (man2 & 0x000FFFFFFFFFFFFF) | // (1 << 52) - 1.\n (exp2_bits << 52) | //\n (h->negative ? 0x8000000000000000 : 0); // (1 << 63).\n\n wuffs_base__result_f64 ret;\n ret.status.repr = NULL;\n ret.value = wuffs_base__ieee_754_bit_representation__to_f64(bits);\n return ret;\n } while (0);\n\nzero:\n do {\n uint64_t bits = h->negative ? 0x8000000000000000 : 0;\n\n wuffs_base__result_f64 ret;\n ret.status.repr = NULL;\n ret.value = wuffs_base__ieee_754_bit_representation__to_f64(bits);\n return ret;\n } while (0);\n\ninfinity:\n do {\n if (options & WUFFS_BASE__PARSE_NUMBER_FXX__REJECT_INF_AND_NAN) {\n wuffs_base__result_f64 ret;\n ret.status.repr = wuffs_base__error__bad_argument;\n ret.value = 0;\n return ret;\n }\n\n uint64_t bits = h->negative ? 0xFFF0000000000000 : 0x7FF0000000000000;\n\n wuffs_base__result_f64 ret;\n ret.status.repr = NULL;\n ret.value = wuffs_base__ieee_754_" +
+ "bit_representation__to_f64(bits);\n return ret;\n } while (0);\n}\n\nstatic inline bool //\nwuffs_base__private_implementation__is_decimal_digit(uint8_t c) {\n return ('0' <= c) && (c <= '9');\n}\n\nWUFFS_BASE__MAYBE_STATIC wuffs_base__result_f64 //\nwuffs_base__parse_number_f64(wuffs_base__slice_u8 s, uint32_t options) {\n // In practice, almost all \"dd.ddddE±xxx\" numbers can be represented\n // losslessly by a uint64_t mantissa \"dddddd\" and an int32_t base-10\n // exponent, adjusting \"xxx\" for the position (if present) of the decimal\n // separator '.' or ','.\n //\n // This (u64 man, i32 exp10) data structure is superficially similar to the\n // \"Do It Yourself Floating Point\" type from Loitsch (†), but the exponent\n // here is base-10, not base-2.\n //\n // If s's number fits in a (man, exp10), parse that pair with the Eisel\n // algorithm. If not, or if Eisel fails, parsing s with the fallback\n // algorithm is slower but comprehensive.\n //\n // † \"Printing Floating-Point Numbers Quickly and Accuratel" +
+ "y with Integers\"\n // (https://www.cs.tufts.edu/~nr/cs257/archive/florian-loitsch/printf.pdf).\n // Florian Loitsch is also the primary contributor to\n // https://github.com/google/double-conversion\n do {\n // Calculating that (man, exp10) pair needs to stay within s's bounds.\n // Provided that s isn't extremely long, work on a NUL-terminated copy of\n // s's contents. The NUL byte isn't a valid part of \"±dd.ddddE±xxx\".\n //\n // As the pointer p walks the contents, it's faster to repeatedly check \"is\n // *p a valid digit\" than \"is p within bounds and *p a valid digit\".\n if (s.len >= 256) {\n goto fallback;\n }\n uint8_t z[256];\n memcpy(&z[0], s.ptr, s.len);\n z[s.len] = 0;\n const uint8_t* p = &z[0];\n\n // Look for a leading minus sign. Technically, we could also look for an\n // optional plus sign, but the \"script/process-json-numbers.c with -p\"\n // benchmark is noticably slower if we do. It's optional and, in practice,\n // usually absent. Let the fallback catch" +
+ " it.\n bool negative = (*p == '-');\n if (negative) {\n p++;\n }\n\n // After walking \"dd.dddd\", comparing p later with p now will produce the\n // number of \"d\"s and \".\"s.\n const uint8_t* const start_of_digits_ptr = p;\n\n // Walk the \"d\"s before a '.', 'E', NUL byte, etc. If it starts with '0',\n // it must be a single '0'. If it starts with a non-zero decimal digit, it\n // can be a sequence of decimal digits.\n //\n // Update the man variable during the walk. It's OK if man overflows now.\n // We'll detect that later.\n uint64_t man;\n if (*p == '0') {\n man = 0;\n p++;\n if (wuffs_base__private_implementation__is_decimal_digit(*p)) {\n goto fallback;\n }\n } else if (wuffs_base__private_implementation__is_decimal_digit(*p)) {\n man = ((uint8_t)(*p - '0'));\n p++;\n for (; wuffs_base__private_implementation__is_decimal_digit(*p); p++) {\n man = (10 * man) + ((uint8_t)(*p - '0'));\n }\n } else {\n goto fallback;\n }\n\n /" +
+ "/ Walk the \"d\"s after the optional decimal separator ('.' or ','),\n // updating the man and exp10 variables.\n int32_t exp10 = 0;\n if (*p ==\n ((options & WUFFS_BASE__PARSE_NUMBER_FXX__DECIMAL_SEPARATOR_IS_A_COMMA)\n ? ','\n : '.')) {\n p++;\n const uint8_t* first_after_separator_ptr = p;\n if (!wuffs_base__private_implementation__is_decimal_digit(*p)) {\n goto fallback;\n }\n man = (10 * man) + ((uint8_t)(*p - '0'));\n p++;\n for (; wuffs_base__private_implementation__is_decimal_digit(*p); p++) {\n man = (10 * man) + ((uint8_t)(*p - '0'));\n }\n exp10 = ((int32_t)(first_after_separator_ptr - p));\n }\n\n // Count the number of digits:\n // - for an input of \"314159\", digit_count is 6.\n // - for an input of \"3.14159\", digit_count is 7.\n //\n // This is off-by-one if there is a decimal separator. That's OK for now.\n // We'll correct for that later. The \"script/process-json-numbers.c with\n // -p\" benchmark " +
+ "is noticably slower if we try to correct for that now.\n uint32_t digit_count = (uint32_t)(p - start_of_digits_ptr);\n\n // Update exp10 for the optional exponent, starting with 'E' or 'e'.\n if ((*p | 0x20) == 'e') {\n p++;\n int32_t exp_sign = +1;\n if (*p == '-') {\n p++;\n exp_sign = -1;\n } else if (*p == '+') {\n p++;\n }\n if (!wuffs_base__private_implementation__is_decimal_digit(*p)) {\n goto fallback;\n }\n int32_t exp_num = ((uint8_t)(*p - '0'));\n p++;\n // The rest of the exp_num walking has a peculiar control flow but, once\n // again, the \"script/process-json-numbers.c with -p\" benchmark is\n // sensitive to alternative formulations.\n if (wuffs_base__private_implementation__is_decimal_digit(*p)) {\n exp_num = (10 * exp_num) + ((uint8_t)(*p - '0'));\n p++;\n }\n if (wuffs_base__private_implementation__is_decimal_digit(*p)) {\n exp_num = (10 * exp_num) + ((uint8_t)(*p - '0'));\n p++;\n " +
+ " }\n while (wuffs_base__private_implementation__is_decimal_digit(*p)) {\n if (exp_num > 0x1000000) {\n goto fallback;\n }\n exp_num = (10 * exp_num) + ((uint8_t)(*p - '0'));\n p++;\n }\n exp10 += exp_sign * exp_num;\n }\n\n // The Wuffs API is that the original slice has no trailing data. It also\n // allows underscores, which we don't catch here but the fallback should.\n if (p != &z[s.len]) {\n goto fallback;\n }\n\n // Check that the uint64_t typed man variable has not overflowed, based on\n // digit_count.\n //\n // For reference:\n // - (1 << 63) is 9223372036854775808, which has 19 decimal digits.\n // - (1 << 64) is 18446744073709551616, which has 20 decimal digits.\n // - 19 nines, 9999999999999999999, is 0x8AC7230489E7FFFF, which has 64\n // bits and 16 hexadecimal digits.\n // - 20 nines, 99999999999999999999, is 0x56BC75E2D630FFFFF, which has 67\n // bits and 17 hexadecimal digits.\n if (digit_count" +
+ " > 19) {\n // Even if we have more than 19 pseudo-digits, it's not yet definitely an\n // overflow. Recall that digit_count might be off-by-one (too large) if\n // there's a decimal separator. It will also over-report the number of\n // meaningful digits if the input looks something like \"0.000dddExxx\".\n //\n // We adjust by the number of leading '0's and '.'s and re-compare to 19.\n // Once again, technically, we could skip ','s too, but that perturbs the\n // \"script/process-json-numbers.c with -p\" benchmark.\n const uint8_t* q = start_of_digits_ptr;\n for (; (*q == '0') || (*q == '.'); q++) {\n }\n digit_count -= (uint32_t)(q - start_of_digits_ptr);\n if (digit_count > 19) {\n goto fallback;\n }\n }\n\n // The wuffs_base__private_implementation__parse_number_f64_eisel\n // preconditions include that exp10 is in the range -326 ..= 310.\n if ((exp10 < -326) || (310 < exp10)) {\n goto fallback;\n }\n\n // If man and exp10 are small e" +
+ "nough, all three of (man), (10 ** exp10) and\n // (man ** (10 ** exp10)) are exactly representable by a double. We don't\n // need to run the Eisel algorithm.\n if ((-22 <= exp10) && (exp10 <= 22) && ((man >> 53) == 0)) {\n double d = (double)man;\n if (exp10 >= 0) {\n d *= wuffs_base__private_implementation__f64_powers_of_10[+exp10];\n } else {\n d /= wuffs_base__private_implementation__f64_powers_of_10[-exp10];\n }\n wuffs_base__result_f64 ret;\n ret.status.repr = NULL;\n ret.value = negative ? -d : +d;\n return ret;\n }\n\n // The wuffs_base__private_implementation__parse_number_f64_eisel\n // preconditions include that man is non-zero. Parsing \"0\" should be caught\n // by the \"If man and exp10 are small enough\" above, but \"0e99\" might not.\n if (man == 0) {\n goto fallback;\n }\n\n // Our man and exp10 are in range. Run the Eisel algorithm.\n int64_t r =\n wuffs_base__private_implementation__parse_number_f64_eisel(man, exp10);\n i" +
+ "f (r < 0) {\n goto fallback;\n }\n wuffs_base__result_f64 ret;\n ret.status.repr = NULL;\n ret.value = wuffs_base__ieee_754_bit_representation__to_f64(\n ((uint64_t)r) | (((uint64_t)negative) << 63));\n return ret;\n } while (0);\n\nfallback:\n do {\n wuffs_base__private_implementation__high_prec_dec h;\n wuffs_base__status status =\n wuffs_base__private_implementation__high_prec_dec__parse(&h, s,\n options);\n if (status.repr) {\n return wuffs_base__private_implementation__parse_number_f64_special(\n s, options);\n }\n return wuffs_base__private_implementation__high_prec_dec__to_f64(&h,\n options);\n } while (0);\n}\n\n" +
"" +
"// --------\n\nstatic inline size_t //\nwuffs_base__private_implementation__render_inf(wuffs_base__slice_u8 dst,\n bool neg,\n uint32_t options) {\n if (neg) {\n if (dst.len < 4) {\n return 0;\n }\n wuffs_base__store_u32le__no_bounds_check(dst.ptr, 0x666E492D); // '-Inf'le.\n return 4;\n }\n\n if (options & WUFFS_BASE__RENDER_NUMBER_XXX__LEADING_PLUS_SIGN) {\n if (dst.len < 4) {\n return 0;\n }\n wuffs_base__store_u32le__no_bounds_check(dst.ptr, 0x666E492B); // '+Inf'le.\n return 4;\n }\n\n if (dst.len < 3) {\n return 0;\n }\n wuffs_base__store_u24le__no_bounds_check(dst.ptr, 0x666E49); // 'Inf'le.\n return 3;\n}\n\nstatic inline size_t //\nwuffs_base__private_implementation__render_nan(wuffs_base__slice_u8 dst) {\n if (dst.len < 3) {\n return 0;\n }\n wuffs_base__store_u24le__no_bounds_check(dst.ptr, 0x4E614E); // 'NaN'le.\n return 3;\n}\n\nstatic size_t //\nwuffs_base__private_implementation__high" +
"_prec_dec__render_exponent_absent(\n wuffs_base__slice_u8 dst,\n wuffs_base__private_implementation__high_prec_dec* h,\n uint32_t precision,\n uint32_t options) {\n size_t n = (h->negative ||\n (options & WUFFS_BASE__RENDER_NUMBER_XXX__LEADING_PLUS_SIGN))\n ? 1\n : 0;\n if (h->decimal_point <= 0) {\n n += 1;\n } else {\n n += (size_t)(h->decimal_point);\n }\n if (precision > 0) {\n n += precision + 1; // +1 for the '.'.\n }\n\n // Don't modify dst if the formatted number won't fit.\n if (n > dst.len) {\n return 0;\n }\n\n // Align-left or align-right.\n uint8_t* ptr = (options & WUFFS_BASE__RENDER_NUMBER_XXX__ALIGN_RIGHT)\n ? &dst.ptr[dst.len - n]\n : &dst.ptr[0];\n\n // Leading \"±\".\n if (h->negative) {\n *ptr++ = '-';\n } else if (options & WUFFS_BASE__RENDER_NUMBER_XXX__LEADING_PLUS_SIGN) {\n *ptr++ = '+';\n }\n\n // Integral digits.\n if (h->decimal_point <= 0) {\n *ptr++ = '0';\n } else {\n uint32_t m =\n" +
diff --git a/release/c/wuffs-unsupported-snapshot.c b/release/c/wuffs-unsupported-snapshot.c
index 53252dd..b096523 100644
--- a/release/c/wuffs-unsupported-snapshot.c
+++ b/release/c/wuffs-unsupported-snapshot.c
@@ -10858,15 +10858,19 @@
static wuffs_base__result_f64 //
wuffs_base__private_implementation__parse_number_f64_special(
wuffs_base__slice_u8 s,
- const char* fallback_status_repr) {
+ uint32_t options) {
do {
+ if (options & WUFFS_BASE__PARSE_NUMBER_FXX__REJECT_INF_AND_NAN) {
+ goto fail;
+ }
+
uint8_t* p = s.ptr;
uint8_t* q = s.ptr + s.len;
for (; (p < q) && (*p == '_'); p++) {
}
if (p >= q) {
- goto fallback;
+ goto fail;
}
// Parse sign.
@@ -10884,7 +10888,7 @@
}
} while (0);
if (p >= q) {
- goto fallback;
+ goto fail;
}
bool nan = false;
@@ -10894,7 +10898,7 @@
if (((q - p) < 3) || //
((p[1] != 'N') && (p[1] != 'n')) || //
((p[2] != 'F') && (p[2] != 'f'))) {
- goto fallback;
+ goto fail;
}
p += 3;
@@ -10906,21 +10910,21 @@
((p[2] != 'I') && (p[2] != 'i')) || //
((p[3] != 'T') && (p[3] != 't')) || //
((p[4] != 'Y') && (p[4] != 'y'))) {
- goto fallback;
+ goto fail;
}
p += 5;
if ((p >= q) || (*p == '_')) {
break;
}
- goto fallback;
+ goto fail;
case 'N':
case 'n':
if (((q - p) < 3) || //
((p[1] != 'A') && (p[1] != 'a')) || //
((p[2] != 'N') && (p[2] != 'n'))) {
- goto fallback;
+ goto fail;
}
p += 3;
@@ -10928,17 +10932,17 @@
nan = true;
break;
}
- goto fallback;
+ goto fail;
default:
- goto fallback;
+ goto fail;
}
// Finish.
for (; (p < q) && (*p == '_'); p++) {
}
if (p != q) {
- goto fallback;
+ goto fail;
}
wuffs_base__result_f64 ret;
ret.status.repr = NULL;
@@ -10948,10 +10952,10 @@
return ret;
} while (0);
-fallback:
+fail:
do {
wuffs_base__result_f64 ret;
- ret.status.repr = fallback_status_repr;
+ ret.status.repr = wuffs_base__error__bad_argument;
ret.value = 0;
return ret;
} while (0);
@@ -10959,7 +10963,8 @@
WUFFS_BASE__MAYBE_STATIC wuffs_base__result_f64 //
wuffs_base__private_implementation__high_prec_dec__to_f64(
- wuffs_base__private_implementation__high_prec_dec* h) {
+ wuffs_base__private_implementation__high_prec_dec* h,
+ uint32_t options) {
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
@@ -11107,6 +11112,13 @@
infinity:
do {
+ if (options & WUFFS_BASE__PARSE_NUMBER_FXX__REJECT_INF_AND_NAN) {
+ wuffs_base__result_f64 ret;
+ ret.status.repr = wuffs_base__error__bad_argument;
+ ret.value = 0;
+ return ret;
+ }
+
uint64_t bits = h->negative ? 0xFFF0000000000000 : 0x7FF0000000000000;
wuffs_base__result_f64 ret;
@@ -11340,9 +11352,10 @@
options);
if (status.repr) {
return wuffs_base__private_implementation__parse_number_f64_special(
- s, status.repr);
+ s, options);
}
- return wuffs_base__private_implementation__high_prec_dec__to_f64(&h);
+ return wuffs_base__private_implementation__high_prec_dec__to_f64(&h,
+ options);
} while (0);
}
diff --git a/test/c/std/json.c b/test/c/std/json.c
index 809a05e..e4663fd 100644
--- a/test/c/std/json.c
+++ b/test/c/std/json.c
@@ -384,7 +384,7 @@
CHECK_STATUS("DECIMAL_SEPARATOR_IS_A_COMMA on", status);
wuffs_base__result_f64 r =
- wuffs_base__private_implementation__high_prec_dec__to_f64(&hpd);
+ wuffs_base__private_implementation__high_prec_dec__to_f64(&hpd, 0);
uint64_t have =
wuffs_base__ieee_754_bit_representation__from_f64(r.value);
uint64_t want = 0x3FFC000000000000;
@@ -396,6 +396,33 @@
}
}
+ // Test WUFFS_BASE__PARSE_NUMBER_FXX__REJECT_INF_AND_NAN, based on calling
+ // wuffs_base__parse_number_f64. It does not call
+ // wuffs_base__private_implementation__high_prec_dec__parse directly.
+ {
+ int o;
+ for (o = 0; o < 4; o++) {
+ const char* str = (o & 2) ? "1e999" : "nan";
+ wuffs_base__result_f64 r = wuffs_base__parse_number_f64(
+ wuffs_base__make_slice_u8((void*)str, strlen(str)),
+ ((o & 1) ? WUFFS_BASE__PARSE_NUMBER_FXX__REJECT_INF_AND_NAN
+ : WUFFS_BASE__PARSE_NUMBER_XXX__DEFAULT_OPTIONS));
+
+ if (o & 1) {
+ if (r.status.repr != wuffs_base__error__bad_argument) {
+ RETURN_FAIL("REJECT_INF_AND_NAN off: have \"%s\", want \"%s\"",
+ r.status.repr, wuffs_base__error__bad_argument);
+ }
+ continue;
+ }
+
+ if (r.status.repr != NULL) {
+ RETURN_FAIL("REJECT_INF_AND_NAN on: have \"%s\", want NULL",
+ r.status.repr);
+ }
+ }
+ }
+
return NULL;
}