| Index: runtime/vm/object.cc
|
| diff --git a/runtime/vm/object.cc b/runtime/vm/object.cc
|
| index 5dc09dd7e5c5e4afedd5e9abae89ad005309f24a..796024d9e07f7189e476060de1891c515b01756f 100644
|
| --- a/runtime/vm/object.cc
|
| +++ b/runtime/vm/object.cc
|
| @@ -2235,7 +2235,7 @@ static bool MatchesAccessorName(const String& name,
|
| return false;
|
| }
|
| for (intptr_t i = 0; i < prefix_length; i++) {
|
| - if (name.CharAt(i) != prefix[i]) {
|
| + if (name.CharAt(i) != static_cast<int32_t>(prefix[i])) {
|
| return false;
|
| }
|
| }
|
| @@ -9163,8 +9163,7 @@ const char* Integer::ToCString() const {
|
|
|
|
|
| RawInteger* Integer::New(const String& str, Heap::Space space) {
|
| - // We are not supposed to have integers represented as two byte or
|
| - // four byte strings.
|
| + // We are not supposed to have integers represented as two byte strings.
|
| ASSERT(str.IsOneByteString());
|
| int64_t value;
|
| if (!OS::StringToInt64(str.ToCString(), &value)) {
|
| @@ -9927,7 +9926,7 @@ intptr_t String::Hash(const uint16_t* characters, intptr_t len) {
|
| }
|
|
|
|
|
| -intptr_t String::Hash(const uint32_t* characters, intptr_t len) {
|
| +intptr_t String::Hash(const int32_t* characters, intptr_t len) {
|
| return HashImpl(characters, len);
|
| }
|
|
|
| @@ -10002,8 +10001,13 @@ bool String::Equals(const char* str) const {
|
| intptr_t consumed = Utf8::Decode(reinterpret_cast<const uint8_t*>(str),
|
| len,
|
| &ch);
|
| - if (consumed == 0 || this->CharAt(i) != ch) {
|
| - return false;
|
| + if (consumed == 0) return false;
|
| +
|
| + if (ch <= Utf16::kMaxCodeUnit) {
|
| + if (this->CharAt(i) != ch) return false;
|
| + } else {
|
| + if (Utf16::CodePointAt(*this, i) != ch) return false;
|
| + i++;
|
| }
|
| str += consumed;
|
| len -= consumed;
|
| @@ -10042,32 +10046,19 @@ bool String::Equals(const uint16_t* characters, intptr_t len) const {
|
| }
|
|
|
|
|
| -bool String::Equals(const uint32_t* characters, intptr_t len) const {
|
| - if (len != this->Length()) {
|
| - // Lengths don't match.
|
| - return false;
|
| - }
|
| -
|
| - for (intptr_t i = 0; i < len; i++) {
|
| - if (this->CharAt(i) != static_cast<int32_t>(characters[i])) {
|
| - return false;
|
| - }
|
| - }
|
| - return true;
|
| -}
|
| -
|
| -
|
| intptr_t String::CompareTo(const String& other) const {
|
| const intptr_t this_len = this->Length();
|
| const intptr_t other_len = other.IsNull() ? 0 : other.Length();
|
| const intptr_t len = (this_len < other_len) ? this_len : other_len;
|
| + // UTF-16 has the high surrogate before the low surrogate so we can compare
|
| + // one code unit at a time for efficiency and still get the right ordering.
|
| for (intptr_t i = 0; i < len; i++) {
|
| - int32_t this_code_point = this->CharAt(i);
|
| - int32_t other_code_point = other.CharAt(i);
|
| - if (this_code_point < other_code_point) {
|
| + int32_t this_code_unit = this->CharAt(i);
|
| + int32_t other_code_unit = other.CharAt(i);
|
| + if (this_code_unit < other_code_unit) {
|
| return -1;
|
| }
|
| - if (this_code_point > other_code_point) {
|
| + if (this_code_unit > other_code_unit) {
|
| return 1;
|
| }
|
| }
|
| @@ -10111,7 +10102,7 @@ RawString* String::New(const uint8_t* utf8_array,
|
| intptr_t array_len,
|
| Heap::Space space) {
|
| Utf8::Type type;
|
| - intptr_t len = Utf8::CodePointCount(utf8_array, array_len, &type);
|
| + intptr_t len = Utf8::CodeUnitCount(utf8_array, array_len, &type);
|
| if (type == Utf8::kLatin1) {
|
| const String& strobj = String::Handle(OneByteString::New(len, space));
|
| if (len > 0) {
|
| @@ -10147,7 +10138,7 @@ RawString* String::New(const uint16_t* utf16_array,
|
| }
|
|
|
|
|
| -RawString* String::New(const uint32_t* utf32_array,
|
| +RawString* String::New(const int32_t* utf32_array,
|
| intptr_t array_len,
|
| Heap::Space space) {
|
| bool is_one_byte_string = true;
|
| @@ -10513,23 +10504,37 @@ RawString* String::Transform(int32_t (*mapping)(int32_t ch),
|
| bool has_mapping = false;
|
| int32_t dst_max = 0;
|
| intptr_t len = str.Length();
|
| + intptr_t out_len = 0;
|
| // TODO(cshapiro): assume a transform is required, rollback if not.
|
| - for (intptr_t i = 0; i < len; ++i) {
|
| + intptr_t i = 0;
|
| + for (; i < len; ++i) {
|
| int32_t src = str.CharAt(i);
|
| + if (Utf16::IsSurrogate(src)) break;
|
| + int32_t dst = mapping(src);
|
| + if (src != dst) {
|
| + has_mapping = true;
|
| + }
|
| + dst_max = Utils::Maximum(dst_max, dst);
|
| + out_len += dst > Utf16::kMaxCodeUnit ? 2 : 1;
|
| + }
|
| + for (; i < len; ++i) {
|
| + int32_t src = Utf16::CodePointAt(str, i);
|
| int32_t dst = mapping(src);
|
| if (src != dst) {
|
| has_mapping = true;
|
| }
|
| dst_max = Utils::Maximum(dst_max, dst);
|
| + out_len += dst > Utf16::kMaxCodeUnit ? 2 : 1;
|
| + if (src > Utf16::kMaxCodeUnit) ++i;
|
| }
|
| if (!has_mapping) {
|
| return str.raw();
|
| }
|
| if (dst_max <= 0xFF) {
|
| - return OneByteString::Transform(mapping, str, space);
|
| + return OneByteString::Transform(mapping, str, out_len, space);
|
| }
|
| ASSERT(dst_max > 0xFF);
|
| - return TwoByteString::Transform(mapping, str, space);
|
| + return TwoByteString::Transform(mapping, str, out_len, space);
|
| }
|
|
|
|
|
| @@ -10683,7 +10688,7 @@ RawOneByteString* OneByteString::New(const uint16_t* characters,
|
| }
|
|
|
|
|
| -RawOneByteString* OneByteString::New(const uint32_t* characters,
|
| +RawOneByteString* OneByteString::New(const int32_t* characters,
|
| intptr_t len,
|
| Heap::Space space) {
|
| const String& result = String::Handle(OneByteString::New(len, space));
|
| @@ -10736,14 +10741,18 @@ RawOneByteString* OneByteString::ConcatAll(const Array& strings,
|
|
|
| RawOneByteString* OneByteString::Transform(int32_t (*mapping)(int32_t ch),
|
| const String& str,
|
| + intptr_t out_length,
|
| Heap::Space space) {
|
| ASSERT(!str.IsNull());
|
| intptr_t len = str.Length();
|
| - const String& result = String::Handle(OneByteString::New(len, space));
|
| - for (intptr_t i = 0; i < len; ++i) {
|
| - int32_t ch = mapping(str.CharAt(i));
|
| - ASSERT(ch >= 0 && ch <= 0xFF);
|
| - *CharAddr(result, i) = ch;
|
| + const String& result =
|
| + String::Handle(OneByteString::New(out_length, space));
|
| + for (intptr_t i = 0, j = 0; i < len; ++i, j++) {
|
| + int32_t old_ch = str.CharAt(i);
|
| + if (old_ch > Utf16::kMaxCodeUnit) i++;
|
| + int32_t ch = mapping(old_ch);
|
| + ASSERT(ch <= 0xFF);
|
| + *CharAddr(result, j) = ch;
|
| }
|
| return OneByteString::raw(result);
|
| }
|
| @@ -10818,7 +10827,7 @@ RawTwoByteString* TwoByteString::New(const uint16_t* utf16_array,
|
|
|
|
|
| RawTwoByteString* TwoByteString::New(intptr_t utf16_len,
|
| - const uint32_t* utf32_array,
|
| + const int32_t* utf32_array,
|
| intptr_t array_len,
|
| Heap::Space space) {
|
| ASSERT((array_len > 0) && (utf16_len >= array_len));
|
| @@ -10827,9 +10836,11 @@ RawTwoByteString* TwoByteString::New(intptr_t utf16_len,
|
| NoGCScope no_gc;
|
| intptr_t j = 0;
|
| for (intptr_t i = 0; i < array_len; ++i) {
|
| - if (utf32_array[i] > 0xffff) {
|
| + int32_t code_point = utf32_array[i];
|
| + if (code_point > Utf16::kMaxCodeUnit) {
|
| ASSERT(j < (utf16_len - 1));
|
| - Utf8::ConvertUTF32ToUTF16(utf32_array[i], CharAddr(result, j));
|
| + *CharAddr(result, j) = Utf16::LeadFromCodePoint(code_point);
|
| + *CharAddr(result, j + 1) = Utf16::TrailFromCodePoint(code_point);
|
| j += 2;
|
| } else {
|
| ASSERT(j < utf16_len);
|
| @@ -10883,14 +10894,25 @@ RawTwoByteString* TwoByteString::ConcatAll(const Array& strings,
|
|
|
| RawTwoByteString* TwoByteString::Transform(int32_t (*mapping)(int32_t ch),
|
| const String& str,
|
| + intptr_t out_length,
|
| Heap::Space space) {
|
| ASSERT(!str.IsNull());
|
| intptr_t len = str.Length();
|
| - const String& result = String::Handle(TwoByteString::New(len, space));
|
| - for (intptr_t i = 0; i < len; ++i) {
|
| - int32_t ch = mapping(str.CharAt(i));
|
| - ASSERT(ch >= 0 && ch <= 0xFFFF);
|
| - *CharAddr(result, i) = ch;
|
| + const String& result =
|
| + String::Handle(TwoByteString::New(out_length, space));
|
| + for (intptr_t i = 0, j = 0; i < len; ++i, j++) {
|
| + int32_t old_ch = Utf16::CodePointAt(str, i);
|
| + if (old_ch > Utf16::kMaxCodeUnit) i++;
|
| + int32_t ch = mapping(old_ch);
|
| + ASSERT(ch <= Utf16::kMaxCodePoint);
|
| + if (ch <= Utf16::kMaxCodeUnit) {
|
| + *CharAddr(result, j) = ch;
|
| + } else {
|
| + *CharAddr(result, j) = Utf16::LeadFromCodePoint(ch);
|
| + *CharAddr(result, j + 1) = Utf16::TrailFromCodePoint(ch);
|
| + ++j;
|
| + }
|
| + ASSERT(j <= out_length);
|
| }
|
| return TwoByteString::raw(result);
|
| }
|
|
|