Index: runtime/vm/object.cc |
=================================================================== |
--- runtime/vm/object.cc (revision 38859) |
+++ runtime/vm/object.cc (working copy) |
@@ -6858,28 +6858,26 @@ |
RawString* Field::GetterName(const String& field_name) { |
CompilerStats::make_accessor_name++; |
// TODO(koda): Avoid most of these allocations by adding prefix-based lookup |
- // to Symbols. |
+ // to Class::Lookup*. |
return String::Concat(Symbols::GetterPrefix(), field_name); |
} |
RawString* Field::GetterSymbol(const String& field_name) { |
- const String& str = String::Handle(Field::GetterName(field_name)); |
- return Symbols::New(str); |
+ return Symbols::FromConcat(Symbols::GetterPrefix(), field_name); |
} |
RawString* Field::SetterName(const String& field_name) { |
CompilerStats::make_accessor_name++; |
// TODO(koda): Avoid most of these allocations by adding prefix-based lookup |
- // to Symbols. |
+ // to Class::Lookup*. |
return String::Concat(Symbols::SetterPrefix(), field_name); |
} |
RawString* Field::SetterSymbol(const String& field_name) { |
- const String& str = String::Handle(Field::SetterName(field_name)); |
- return Symbols::New(str); |
+ return Symbols::FromConcat(Symbols::SetterPrefix(), field_name); |
} |
@@ -16086,6 +16084,8 @@ |
void Add(int32_t ch) { |
hash_ = CombineHashes(hash_, ch); |
} |
+ void Add(const String& str, intptr_t begin_index, intptr_t len); |
+ |
// Return a non-zero hash of at most 'bits' bits. |
intptr_t Finalize(int bits) { |
ASSERT(1 <= bits && bits <= (kBitsPerWord - 1)); |
@@ -16099,25 +16099,46 @@ |
}; |
-intptr_t String::Hash(const String& str, intptr_t begin_index, intptr_t len) { |
+void StringHasher::Add(const String& str, intptr_t begin_index, intptr_t len) { |
ASSERT(begin_index >= 0); |
ASSERT(len >= 0); |
ASSERT((begin_index + len) <= str.Length()); |
- StringHasher hasher; |
if (str.IsOneByteString()) { |
for (intptr_t i = 0; i < len; i++) { |
- hasher.Add(*OneByteString::CharAddr(str, i + begin_index)); |
+ Add(*OneByteString::CharAddr(str, i + begin_index)); |
} |
} else { |
- CodePointIterator it(str, begin_index, len); |
+ String::CodePointIterator it(str, begin_index, len); |
while (it.Next()) { |
- hasher.Add(it.Current()); |
+ Add(it.Current()); |
} |
} |
+} |
+ |
+ |
+intptr_t String::Hash(const String& str, intptr_t begin_index, intptr_t len) { |
+ StringHasher hasher; |
+ hasher.Add(str, begin_index, len); |
return hasher.Finalize(String::kHashBits); |
} |
+intptr_t String::HashConcat(const String& str1, const String& str2) { |
+ intptr_t len1 = str1.Length(); |
+ // Since String::Hash works at the code point (rune) level, a surrogate pair |
+ // that crosses the boundary between str1 and str2 must be composed. |
+ if (str1.IsTwoByteString() && Utf16::IsLeadSurrogate(str1.CharAt(len1 - 1))) { |
+ const String& temp = String::Handle(String::Concat(str1, str2)); |
+ return temp.Hash(); |
+ } else { |
+ StringHasher hasher; |
+ hasher.Add(str1, 0, len1); |
+ hasher.Add(str2, 0, str2.Length()); |
+ return hasher.Finalize(String::kHashBits); |
+ } |
+} |
+ |
+ |
template<typename T> |
static intptr_t HashImpl(const T* characters, intptr_t len) { |
ASSERT(len >= 0); |
@@ -16294,6 +16315,13 @@ |
} |
+bool String::EqualsConcat(const String& str1, const String& str2) const { |
+ return (Length() == str1.Length() + str2.Length()) && |
+ str1.Equals(*this, 0, str1.Length()) && |
+ str2.Equals(*this, str1.Length(), str2.Length()); |
+} |
+ |
+ |
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(); |