// Return 1 if the non-NULL-terminated string starting with |start| and ending // with |end| starts with the NULL-terminated string |prefix|. template <typename T> // static bool FloatParser<T>::StringStartsWith(constchar* start, constchar* end, constchar* prefix) { while (start < end && *prefix) { if (*start != *prefix) { returnfalse;
}
start++;
prefix++;
} return *prefix == 0;
}
// static template <typename T>
Result FloatParser<T>::ParseFloat(constchar* s, constchar* end,
Uint* out_bits) { // Here is the normal behavior for strtof/strtod: // // input | errno | output | // --------------------------------- // overflow | ERANGE | +-HUGE_VAL | // underflow | ERANGE | 0.0 | // otherwise | 0 | value | // // So normally we need to clear errno before calling strto{f,d}, and check // afterward whether it was set to ERANGE. // // glibc seems to have a bug where // strtof("340282356779733661637539395458142568448") will return HUGE_VAL, // but will not set errno to ERANGE. Since this function is only called when // we know that we have parsed a "normal" number (i.e. not "inf"), we know // that if we ever get HUGE_VAL, it must be overflow. // // The WebAssembly spec also ignores underflow, so we don't need to check for // ERANGE at all.
// WebAssembly floats can contain underscores, but strto* can't parse those, // so remove them first.
assert(s <= end); const size_t kBufferSize = end - s + 1; // +1 for \0. char* buffer = static_cast<char*>(alloca(kBufferSize)); auto buffer_end =
std::copy_if(s, end, buffer, [](char c) -> bool { return c != '_'; });
assert(buffer_end < buffer + kBufferSize);
*buffer_end = 0;
char* endptr; Float value = Traits::Strto(buffer, &endptr); if (endptr != buffer_end ||
(value == Traits::kHugeVal || value == -Traits::kHugeVal)) { return Result::Error;
}
// Loop over the significand; everything up to the 'p'. // This code is a bit nasty because we want to support extra zeroes anywhere // without having to use many significand bits. // e.g. // 0x00000001.0p0 => significand = 1, significand_exponent = 0 // 0x10000000.0p0 => significand = 1, significand_exponent = 28 // 0x0.000001p0 => significand = 1, significand_exponent = -24 bool seen_dot = false; bool seen_trailing_non_zero = false;
Uint significand = 0; int significand_exponent = 0; // Exponent adjustment due to dot placement. for (; s < end; ++s) {
uint32_t digit; if (*s == '_') { continue;
} elseif (*s == '.') {
seen_dot = true;
} elseif (Succeeded(ParseHexdigit(*s, &digit))) { if (Traits::kBits - Clz(significand) <= Traits::kSigPlusOneBits) {
significand = (significand << 4) + digit; if (seen_dot) {
significand_exponent -= 4;
}
} else { if (!seen_trailing_non_zero && digit != 0) {
seen_trailing_non_zero = true;
} if (!seen_dot) {
significand_exponent += 4;
}
}
} else { break;
}
}
if (significand == 0) { // 0 or -0.
*out_bits = Make(is_neg, Traits::kMinExp, 0); return Result::Ok;
}
int exponent = 0; bool exponent_is_neg = false; if (s < end) {
assert(*s == 'p' || *s == 'P');
s++; // Exponent is always positive, but significand_exponent is signed. // significand_exponent_add is negated if exponent will be negative, so it // can be easily summed to see if the exponent is too large (see below). int significand_exponent_add = 0; if (*s == '-') {
exponent_is_neg = true;
significand_exponent_add = -significand_exponent;
s++;
} elseif (*s == '+') {
s++;
significand_exponent_add = significand_exponent;
}
for (; s < end; ++s) { if (*s == '_') { continue;
}
int significand_bits = Traits::kBits - Clz(significand); // -1 for the implicit 1 bit of the significand.
exponent += significand_exponent + significand_bits - 1;
char buffer[Traits::kMaxHexBufferSize]; char* p = buffer; bool is_neg = (bits >> Traits::kSignShift); int exp = ((bits >> Traits::kSigBits) & Traits::kExpMask) - Traits::kExpBias;
Uint sig = bits & Traits::kSigMask;
if (is_neg) {
*p++ = '-';
} if (exp == Traits::kMaxExp) { // Infinity or nan. if (sig == 0) {
strcpy(p, "inf");
p += 3;
} else {
strcpy(p, "nan");
p += 3; if (sig != Traits::kQuietNanTag) {
strcpy(p, ":0x");
p += 3; // Skip leading zeroes. int num_nybbles = kNumNybbles; while ((sig & kTopNybble) == 0) {
sig <<= 4;
num_nybbles--;
} while (num_nybbles) {
Uint nybble = (sig >> kTopNybbleShift) & 0xf;
*p++ = s_hex_digits[nybble];
sig <<= 4;
--num_nybbles;
}
}
}
} else { bool is_zero = sig == 0 && exp == Traits::kMinExp;
strcpy(p, "0x");
p += 2;
*p++ = is_zero ? '0' : '1';
// Shift sig up so the top 4-bits are at the top of the Uint.
sig <<= Traits::kBits - Traits::kSigBits;
if (sig) { if (exp == Traits::kMinExp) { // Subnormal; shift the significand up, and shift out the implicit 1.
Uint leading_zeroes = Clz(sig); if (leading_zeroes < Traits::kSignShift) {
sig <<= leading_zeroes + 1;
} else {
sig = 0;
}
exp -= leading_zeroes;
}
Result ParseUint64(constchar* s, constchar* end, uint64_t* out) { if (s == end) { return Result::Error;
}
uint64_t value = 0; if (*s == '0' && s + 1 < end && s[1] == 'x') {
s += 2; if (s == end) { return Result::Error;
}
constexpr uint64_t kMaxDiv16 = UINT64_MAX / 16;
constexpr uint64_t kMaxMod16 = UINT64_MAX % 16; for (; s < end; ++s) {
uint32_t digit; if (*s == '_') { continue;
}
CHECK_RESULT(ParseHexdigit(*s, &digit)); // Check for overflow. if (value > kMaxDiv16 || (value == kMaxDiv16 && digit > kMaxMod16)) { return Result::Error;
}
value = value * 16 + digit;
}
} else {
constexpr uint64_t kMaxDiv10 = UINT64_MAX / 10;
constexpr uint64_t kMaxMod10 = UINT64_MAX % 10; for (; s < end; ++s) { if (*s == '_') { continue;
}
uint32_t digit = (*s - '0'); if (digit > 9) { return Result::Error;
} // Check for overflow. if (value > kMaxDiv10 || (value == kMaxDiv10 && digit > kMaxMod10)) { return Result::Error;
}
value = value * 10 + digit;
}
} if (s != end) { return Result::Error;
}
*out = value; return Result::Ok;
}
Result ParseInt64(constchar* s, constchar* end,
uint64_t* out,
ParseIntType parse_type) { bool has_sign = false; if (*s == '-' || *s == '+') { if (parse_type == ParseIntType::UnsignedOnly) { return Result::Error;
} if (*s == '-') {
has_sign = true;
}
s++;
}
uint64_t value = 0;
Result result = ParseUint64(s, end, &value); if (has_sign) { // abs(INT64_MIN) == INT64_MAX + 1. if (value > static_cast<uint64_t>(INT64_MAX) + 1) { return Result::Error;
}
value = UINT64_MAX - value + 1;
}
*out = value; return result;
}
namespace {
uint32_t AddWithCarry(uint32_t x, uint32_t y, uint32_t* carry) { // Increments *carry if the addition overflows, otherwise leaves carry alone. if ((0xffffffff - x) < y) {
++*carry;
} return x + y;
}
void Mul10(v128* v) { // Multiply-by-10 decomposes into (x << 3) + (x << 1). We implement those // operations with carrying from smaller quads of the v128 to the larger // quads.
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.