#pragma once
#include "JSCJSValue.h"
#include <wtf/dtoa.h>
namespace JSC {
static const double mantissaOverflowLowerBound = 9007199254740992.0;
ALWAYS_INLINE static int parseDigit(unsigned short c, int radix)
{
int digit = -1;
if (isASCIIDigit(c))
digit = c - '0';
else if (isASCIIUpper(c))
digit = c - 'A' + 10;
else if (isASCIILower(c))
digit = c - 'a' + 10;
if (digit >= radix)
return -1;
return digit;
}
static double parseIntOverflow(const LChar* s, unsigned length, int radix)
{
double number = 0.0;
double radixMultiplier = 1.0;
for (const LChar* p = s + length - 1; p >= s; p--) {
if (radixMultiplier == std::numeric_limits<double>::infinity()) {
if (*p != '0') {
number = std::numeric_limits<double>::infinity();
break;
}
} else {
int digit = parseDigit(*p, radix);
number += digit * radixMultiplier;
}
radixMultiplier *= radix;
}
return number;
}
static double parseIntOverflow(const UChar* s, unsigned length, int radix)
{
double number = 0.0;
double radixMultiplier = 1.0;
for (const UChar* p = s + length - 1; p >= s; p--) {
if (radixMultiplier == std::numeric_limits<double>::infinity()) {
if (*p != '0') {
number = std::numeric_limits<double>::infinity();
break;
}
} else {
int digit = parseDigit(*p, radix);
number += digit * radixMultiplier;
}
radixMultiplier *= radix;
}
return number;
}
static double parseIntOverflow(StringView string, int radix)
{
if (string.is8Bit())
return parseIntOverflow(string.characters8(), string.length(), radix);
return parseIntOverflow(string.characters16(), string.length(), radix);
}
ALWAYS_INLINE static bool isStrWhiteSpace(UChar c)
{
switch (c) {
case 0x0009:
case 0x000A:
case 0x000B:
case 0x000C:
case 0x000D:
case 0x0020:
case 0x00A0:
case 0x180E: case 0x2028:
case 0x2029:
case 0xFEFF:
return true;
default:
return c > 0xFF && u_charType(c) == U_SPACE_SEPARATOR;
}
}
template <typename CharType>
ALWAYS_INLINE
static double parseInt(StringView s, const CharType* data, int radix)
{
int length = s.length();
int p = 0;
while (p < length && isStrWhiteSpace(data[p]))
++p;
double sign = 1;
if (p < length) {
if (data[p] == '+')
++p;
else if (data[p] == '-') {
sign = -1;
++p;
}
}
if ((radix == 0 || radix == 16) && length - p >= 2 && data[p] == '0' && (data[p + 1] == 'x' || data[p + 1] == 'X')) {
radix = 16;
p += 2;
} else if (radix == 0)
radix = 10;
if (radix < 2 || radix > 36)
return PNaN;
int firstDigitPosition = p;
bool sawDigit = false;
double number = 0;
while (p < length) {
int digit = parseDigit(data[p], radix);
if (digit == -1)
break;
sawDigit = true;
number *= radix;
number += digit;
++p;
}
if (!sawDigit)
return PNaN;
if (number >= mantissaOverflowLowerBound) {
if (radix == 10) {
size_t parsedLength;
number = parseDouble(s.substring(firstDigitPosition, p - firstDigitPosition), parsedLength);
} else if (radix == 2 || radix == 4 || radix == 8 || radix == 16 || radix == 32)
number = parseIntOverflow(s.substring(firstDigitPosition, p - firstDigitPosition), radix);
}
return sign * number;
}
ALWAYS_INLINE static double parseInt(StringView s, int radix)
{
if (s.is8Bit())
return parseInt(s, s.characters8(), radix);
return parseInt(s, s.characters16(), radix);
}
template<typename CallbackWhenNoException>
static ALWAYS_INLINE typename std::result_of<CallbackWhenNoException(StringView)>::type toStringView(ExecState* exec, JSValue value, CallbackWhenNoException callback)
{
VM& vm = exec->vm();
auto scope = DECLARE_THROW_SCOPE(vm);
JSString* string = value.toStringOrNull(exec);
EXCEPTION_ASSERT(!!scope.exception() == !string);
if (UNLIKELY(!string))
return { };
auto viewWithString = string->viewWithUnderlyingString(exec);
RETURN_IF_EXCEPTION(scope, { });
scope.release();
return callback(viewWithString.view);
}
const char radixDigits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
}