📄 conversions.cc.svn-base
字号:
// Copyright 2006-2008 the V8 project authors. All rights reserved.// Redistribution and use in source and binary forms, with or without// modification, are permitted provided that the following conditions are// met://// * Redistributions of source code must retain the above copyright// notice, this list of conditions and the following disclaimer.// * Redistributions in binary form must reproduce the above// copyright notice, this list of conditions and the following// disclaimer in the documentation and/or other materials provided// with the distribution.// * Neither the name of Google Inc. nor the names of its// contributors may be used to endorse or promote products derived// from this software without specific prior written permission.//// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.#include <stdarg.h>#include "v8.h"#include "conversions-inl.h"#include "factory.h"#include "scanner.h"namespace v8 { namespace internal {int HexValue(uc32 c) { if ('0' <= c && c <= '9') return c - '0'; if ('a' <= c && c <= 'f') return c - 'a' + 10; if ('A' <= c && c <= 'F') return c - 'A' + 10; return -1;}// Provide a common interface to getting a character at a certain// index from a char* or a String object.static inline int GetChar(const char* str, int index) { ASSERT(index >= 0 && index < static_cast<int>(strlen(str))); return str[index];}static inline int GetChar(String* str, int index) { return str->Get(index);}static inline int GetLength(const char* str) { return strlen(str);}static inline int GetLength(String* str) { return str->length();}static inline const char* GetCString(const char* str, int index) { return str + index;}static inline const char* GetCString(String* str, int index) { char* result = NewArray<char>(str->length() + 1); for (int i = index; i < str->length(); i++) { if (str->Get(i) <= 127) { result[i - index] = static_cast<char>(str->Get(i)); } else { result[i - index] = 127; // Force number parsing to fail. } } result[str->length() - index] = '\0'; return result;}static inline void ReleaseCString(const char* original, const char* str) {}static inline void ReleaseCString(String* original, const char* str) { DeleteArray(const_cast<char *>(str));}static inline bool IsSpace(const char* str, int index) { ASSERT(index >= 0 && index < static_cast<int>(strlen(str))); return Scanner::kIsWhiteSpace.get(str[index]);}static inline bool IsSpace(String* str, int index) { return Scanner::kIsWhiteSpace.get(str->Get(index));}static inline bool SubStringEquals(const char* str, int index, const char* other) { return strncmp(str + index, other, strlen(other)) != 0;}static inline bool SubStringEquals(String* str, int index, const char* other) { HandleScope scope; int len = strlen(other); int end = index + len < str->length() ? index + len : str->length(); Handle<String> slice = Factory::NewStringSlice(Handle<String>(str), index, end); return slice->IsEqualTo(Vector<const char>(other, len));}// Check if a string should be parsed as an octal number. The string// can be either a char* or a String*.template<class S>static bool ShouldParseOctal(S* s, int i) { int index = i; int len = GetLength(s); if (index < len && GetChar(s, index) != '0') return false; // If the first real character (following '0') is not an octal // digit, bail out early. This also takes care of numbers of the // forms 0.xxx and 0exxx by not allowing the first 0 to be // interpreted as an octal. index++; if (index < len) { int d = GetChar(s, index) - '0'; if (d < 0 || d > 7) return false; } else { return false; } // Traverse all digits (including the first). If there is an octal // prefix which is not a part of a longer decimal prefix, we return // true. Otherwise, false is returned. while (index < len) { int d = GetChar(s, index++) - '0'; if (d == 8 || d == 9) return false; if (d < 0 || d > 7) return true; } return true;}extern "C" double gay_strtod(const char* s00, const char** se);// Parse an int from a string starting a given index and in a given// radix. The string can be either a char* or a String*.template <class S>static int InternalStringToInt(S* s, int i, int radix, double* value) { int len = GetLength(s); // Setup limits for computing the value. ASSERT(2 <= radix && radix <= 36); int lim_0 = '0' + (radix < 10 ? radix : 10); int lim_a = 'a' + (radix - 10); int lim_A = 'A' + (radix - 10); // NOTE: The code for computing the value may seem a bit complex at // first glance. It is structured to use 32-bit multiply-and-add // loops as long as possible to avoid loosing precision. double v = 0.0; int j; for (j = i; j < len;) { // Parse the longest part of the string starting at index j // possible while keeping the multiplier, and thus the part // itself, within 32 bits. uint32_t part = 0, multiplier = 1; int k; for (k = j; k < len; k++) { int c = GetChar(s, k); if (c >= '0' && c < lim_0) { c = c - '0'; } else if (c >= 'a' && c < lim_a) { c = c - 'a' + 10; } else if (c >= 'A' && c < lim_A) { c = c - 'A' + 10; } else { break; } // Update the value of the part as long as the multiplier fits // in 32 bits. When we can't guarantee that the next iteration // will not overflow the multiplier, we stop parsing the part // by leaving the loop. static const uint32_t kMaximumMultiplier = 0xffffffffU / 36; uint32_t m = multiplier * radix; if (m > kMaximumMultiplier) break; part = part * radix + c; multiplier = m; ASSERT(multiplier > part); } // Compute the number of part digits. If no digits were parsed; // we're done parsing the entire string. int digits = k - j; if (digits == 0) break; // Update the value and skip the part in the string. ASSERT(multiplier == pow(static_cast<double>(radix), static_cast<double>(digits))); v = v * multiplier + part; j = k; } // If the resulting value is larger than 2^53 the value does not fit // in the mantissa of the double and there is a loss of precision. // When the value is larger than 2^53 the rounding depends on the // code generation. If the code generator spills the double value // it uses 64 bits and if it does not it uses 80 bits. // // If there is a potential for overflow we resort to strtod for // radix 10 numbers to get higher precision. For numbers in another // radix we live with the loss of precision. static const double kPreciseConversionLimit = 9007199254740992.0; if (radix == 10 && v > kPreciseConversionLimit) { const char* cstr = GetCString(s, i); const char* end; v = gay_strtod(cstr, &end); ReleaseCString(s, cstr); } *value = v; return j;}int StringToInt(String* str, int index, int radix, double* value) { return InternalStringToInt(str, index, radix, value);}int StringToInt(const char* str, int index, int radix, double* value) { return InternalStringToInt(const_cast<char*>(str), index, radix, value);}static const double JUNK_STRING_VALUE = OS::nan_value();// Convert a string to a double value. The string can be either a// char* or a String*.template<class S>static double InternalStringToDouble(S* str, int flags, double empty_string_val) { double result = 0.0; int index = 0; int len = GetLength(str); // Skip leading spaces. while ((index < len) && IsSpace(str, index)) index++; // Is the string empty? if (index >= len) return empty_string_val; // Get the first character. uint16_t first = GetChar(str, index); // Numbers can only start with '-', '+', '.', 'I' (Infinity), or a digit. if (first != '-' && first != '+' && first != '.' && first != 'I' && (first > '9' || first < '0')) { return JUNK_STRING_VALUE; } // Compute sign of result based on first character. int sign = 1; if (first == '-') { sign = -1; index++; // String only containing a '-' are junk chars. if (index == len) return JUNK_STRING_VALUE; } // do we have a hex number? // (since the string is 0-terminated, it's ok to look one char beyond the end) if ((flags & ALLOW_HEX) != 0 && (index + 1) < len && GetChar(str, index) == '0' && (GetChar(str, index + 1) == 'x' || GetChar(str, index + 1) == 'X')) { index += 2; index = StringToInt(str, index, 16, &result); } else if ((flags & ALLOW_OCTALS) != 0 && ShouldParseOctal(str, index)) { // NOTE: We optimistically try to parse the number as an octal (if // we're allowed to), even though this is not as dictated by // ECMA-262. The reason for doing this is compatibility with IE and // Firefox. index = StringToInt(str, index, 8, &result); } else { const char* cstr = GetCString(str, index); const char* end; // Optimistically parse the number and then, if that fails, // check if it might have been {+,-,}Infinity. result = gay_strtod(cstr, &end); ReleaseCString(str, cstr); if (result != 0.0 || end != cstr) { // It appears that strtod worked index += end - cstr; } else { // Check for {+,-,}Infinity bool is_negative = (GetChar(str, index) == '-'); if (GetChar(str, index) == '+' || GetChar(str, index) == '-') index++; if (!SubStringEquals(str, index, "Infinity")) return JUNK_STRING_VALUE; result = is_negative ? -INFINITY : INFINITY; index += 8; } } if ((flags & ALLOW_TRAILING_JUNK) == 0) { // skip trailing spaces while ((index < len) && IsSpace(str, index)) index++; // string ending with junk? if (index < len) return JUNK_STRING_VALUE; } return sign * result;}double StringToDouble(String* str, int flags, double empty_string_val) { return InternalStringToDouble(str, flags, empty_string_val);}double StringToDouble(const char* str, int flags, double empty_string_val) { return InternalStringToDouble(str, flags, empty_string_val);}extern "C" char* dtoa(double d, int mode, int ndigits, int* decpt, int* sign, char** rve);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -