Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 23 additions & 7 deletions double-conversion/string-to-double.cc
Original file line number Diff line number Diff line change
Expand Up @@ -51,13 +51,25 @@ namespace double_conversion {

namespace {

inline char ToLower(char ch) {
// Widens an input character to its unsigned code-unit value. Symbol matching
// compares characters in this form, so that a 16-bit input character is never
// truncated into the range of the symbol byte it is compared against.
inline uint32_t CodeUnit(char ch) {
return static_cast<unsigned char>(ch);
}

inline uint32_t CodeUnit(uc16 ch) {
return ch;
}

inline uint32_t ToLower(uint32_t ch) {
if (ch > 0x7F) return ch;
static const std::ctype<char>& cType =
std::use_facet<std::ctype<char> >(std::locale::classic());
return cType.tolower(ch);
return static_cast<unsigned char>(cType.tolower(static_cast<char>(ch)));
}

inline char Pass(char ch) {
inline uint32_t Pass(uint32_t ch) {
return ch;
}

Expand All @@ -66,10 +78,11 @@ static inline bool ConsumeSubStringImpl(Iterator* current,
Iterator end,
const char* substring,
Converter converter) {
DOUBLE_CONVERSION_ASSERT(converter(**current) == *substring);
DOUBLE_CONVERSION_ASSERT(converter(CodeUnit(**current)) == CodeUnit(*substring));
for (substring++; *substring != '\0'; substring++) {
++*current;
if (*current == end || converter(**current) != *substring) {
if (*current == end ||
converter(CodeUnit(**current)) != CodeUnit(*substring)) {
return false;
}
}
Expand All @@ -92,10 +105,13 @@ static bool ConsumeSubString(Iterator* current,
}

// Consumes first character of the str is equal to ch
inline bool ConsumeFirstCharacter(char ch,
template <class Char>
inline bool ConsumeFirstCharacter(Char ch,
const char* str,
bool case_insensitivity) {
return case_insensitivity ? ToLower(ch) == str[0] : ch == str[0];
const uint32_t c = CodeUnit(ch);
const uint32_t first = CodeUnit(str[0]);
return case_insensitivity ? ToLower(c) == first : c == first;
}
} // namespace

Expand Down
54 changes: 54 additions & 0 deletions test/cctest/test-conversions.cc
Original file line number Diff line number Diff line change
Expand Up @@ -6002,6 +6002,60 @@ TEST(StringToDoubleCaseInsensitiveSpecialValues) {
}


TEST(StringToDoubleNonAsciiSpecialValues) {
int processed = 0;

// Use 1.0 as junk_string_value.
StringToDoubleConverter converter(StringToDoubleConverter::NO_FLAGS,
0.0, 1.0, "Infinity", "NaN");

// The ASCII spellings are the only ones that match.
const uc16 nan16[] = { 'N', 'a', 'N' };
CHECK_EQ(Double::NaN(), converter.StringToDouble(nan16, 3, &processed));
CHECK_EQ(3, processed);

const uc16 infinity16[] = { 'I', 'n', 'f', 'i', 'n', 'i', 't', 'y' };
CHECK_EQ(Double::Infinity(),
converter.StringToDouble(infinity16, 8, &processed));
CHECK_EQ(8, processed);

// Characters whose low byte equals a symbol character must not match it.
// U+014E and U+FF4E end in 'N', U+0161 ends in 'a', U+FF49 ends in 'I' and
// U+016E ends in 'n'.
const uc16 nan_lead[] = { 0x014E, 'a', 'N' };
CHECK_EQ(1.0, converter.StringToDouble(nan_lead, 3, &processed));
CHECK_EQ(0, processed);

const uc16 nan_tail[] = { 'N', 0x0161, 'N' };
CHECK_EQ(1.0, converter.StringToDouble(nan_tail, 3, &processed));
CHECK_EQ(0, processed);

const uc16 infinity_lead[] = { 0xFF49, 'n', 'f', 'i', 'n', 'i', 't', 'y' };
CHECK_EQ(1.0, converter.StringToDouble(infinity_lead, 8, &processed));
CHECK_EQ(0, processed);

const uc16 infinity_tail[] = { 'I', 0x016E, 'f', 'i', 'n', 'i', 't', 'y' };
CHECK_EQ(1.0, converter.StringToDouble(infinity_tail, 8, &processed));
CHECK_EQ(0, processed);

// The same holds when the symbols are matched case-insensitively.
const int ci_flags = StringToDoubleConverter::ALLOW_CASE_INSENSITIVITY;
StringToDoubleConverter ci_converter(ci_flags, 0.0, 1.0, "infinity", "nan");

const uc16 nan_ci[] = { 'n', 'a', 'N' };
CHECK_EQ(Double::NaN(), ci_converter.StringToDouble(nan_ci, 3, &processed));
CHECK_EQ(3, processed);

const uc16 nan_ci_lead[] = { 0x014E, 'a', 'n' };
CHECK_EQ(1.0, ci_converter.StringToDouble(nan_ci_lead, 3, &processed));
CHECK_EQ(0, processed);

const uc16 nan_ci_tail[] = { 'n', 'a', 0x014E };
CHECK_EQ(1.0, ci_converter.StringToDouble(nan_ci_tail, 3, &processed));
CHECK_EQ(0, processed);
}


TEST(StringToTemplate) {
// Test StringToDoubleConverter::StringTo<T>.

Expand Down
Loading