Index: src/api.cc |
diff --git a/src/api.cc b/src/api.cc |
index b2dc2e1e943abbd81efadccc18fb6ed5c5f1c299..4cdd77ef05a6908c5cc5ebf0fa3398ab0c1f3e72 100644 |
--- a/src/api.cc |
+++ b/src/api.cc |
@@ -4304,6 +4304,85 @@ bool String::IsOneByte() const { |
} |
+class ContainsOnlyOneByteHelper { |
+ public: |
+ ContainsOnlyOneByteHelper() : is_one_byte_(true) {} |
+ bool Check(i::String* string) { |
+ i::ConsString* cons_string = i::String::VisitFlat(this, string, 0); |
+ if (cons_string == NULL) return is_one_byte_; |
+ return CheckCons(cons_string); |
+ } |
+ void VisitOneByteString(const uint8_t* chars, int length) { |
+ // Nothing to do. |
+ } |
+ // TODO(dcarney): do word aligned read. |
+ void VisitTwoByteString(const uint16_t* chars, int length) { |
+ // Check whole string without breaking. |
+ uint16_t total = 0; |
+ for (int i = 0; i < length; i++) { |
+ total |= chars[i] >> 8; |
+ } |
+ if (total != 0) is_one_byte_ = false; |
+ } |
+ |
+ private: |
+ bool CheckCons(i::ConsString* cons_string) { |
+ while (true) { |
+ // Check left side if flat. |
+ i::String* left = cons_string->first(); |
+ i::ConsString* left_as_cons = |
+ i::String::VisitFlat(this, left, 0); |
+ if (!is_one_byte_) return false; |
+ // Check right side if flat. |
+ i::String* right = cons_string->second(); |
+ i::ConsString* right_as_cons = |
+ i::String::VisitFlat(this, right, 0); |
+ if (!is_one_byte_) return false; |
+ // Standard recurse/iterate trick. |
+ if (left_as_cons != NULL && right_as_cons != NULL) { |
+ if (left->length() < right->length()) { |
+ CheckCons(left_as_cons); |
+ cons_string = right_as_cons; |
+ } else { |
+ CheckCons(right_as_cons); |
+ cons_string = left_as_cons; |
+ } |
+ // Check fast return. |
+ if (!is_one_byte_) return false; |
+ continue; |
+ } |
+ // Descend left in place. |
+ if (left_as_cons != NULL) { |
+ cons_string = left_as_cons; |
+ continue; |
+ } |
+ // Descend right in place. |
+ if (right_as_cons != NULL) { |
+ cons_string = right_as_cons; |
+ continue; |
+ } |
+ // Terminate. |
+ break; |
+ } |
+ return is_one_byte_; |
+ } |
+ bool is_one_byte_; |
+ DISALLOW_COPY_AND_ASSIGN(ContainsOnlyOneByteHelper); |
+}; |
+ |
+ |
+bool String::ContainsOnlyOneByte() const { |
+ i::Handle<i::String> str = Utils::OpenHandle(this); |
+ if (IsDeadCheck(str->GetIsolate(), |
+ "v8::String::ContainsOnlyOneByte()")) { |
+ return false; |
+ } |
+ if (str->HasOnlyOneByteChars()) return true; |
+ ContainsOnlyOneByteHelper helper; |
+ return helper.Check(*str); |
+} |
+ |
+ |
class Utf8LengthHelper : public i::AllStatic { |
public: |
enum State { |