Add equals to C++ String

This is a baby step towards using String instead of StringPiece.

Change-Id: I34baa1c91e99f78151ec1fa9175eb5df30fa0292
diff --git a/src/class_linker.h b/src/class_linker.h
index d6c2f0c..b504095 100644
--- a/src/class_linker.h
+++ b/src/class_linker.h
@@ -206,6 +206,7 @@
   FRIEND_TEST(DexCacheTest, Open);
   friend class ObjectTest;
   FRIEND_TEST(ObjectTest, AllocObjectArray);
+  FRIEND_TEST(ObjectTest, StringEquals);
   DISALLOW_COPY_AND_ASSIGN(ClassLinker);
 };
 
diff --git a/src/object.h b/src/object.h
index 4d68d30..a9bf40f 100644
--- a/src/object.h
+++ b/src/object.h
@@ -1057,11 +1057,11 @@
   // Field order required by test "ValidateFieldOrderOfJavaCppUnionClasses".
   CharArray* array_;
 
-  uint32_t hash_code_;
+  int32_t hash_code_;
 
-  uint32_t offset_;
+  int32_t offset_;
 
-  uint32_t count_;
+  int32_t count_;
 
   static String* Alloc(Class* java_lang_String,
                        Class* char_array,
@@ -1114,14 +1114,25 @@
   }
 
   // The java/lang/String.computeHashCode() algorithm
-  static uint32_t ComputeUtf16Hash(const uint16_t* string_data, size_t string_length) {
-    uint32_t hash = 0;
+  static int32_t ComputeUtf16Hash(const uint16_t* string_data, size_t string_length) {
+    int32_t hash = 0;
     while (string_length--) {
         hash = hash * 31 + *string_data++;
     }
     return hash;
   }
 
+  static bool Equals(const String* string, const char* other) {
+    uint16_t* chars = string->array_->GetChars();
+    for (int32_t i = 0; i < string->count_; i++) {
+      uint16_t c = GetUtf16FromUtf8(&other);
+      if (c == '\0' || c != chars[string->offset_ + i]) {
+        return false;
+      }
+    }
+    return *other == '\0';
+  }
+
  private:
   String();
 };
diff --git a/src/object_test.cc b/src/object_test.cc
index 969378c..7800855 100644
--- a/src/object_test.cc
+++ b/src/object_test.cc
@@ -19,7 +19,7 @@
   void AssertString(size_t length,
                     const char* utf8_in,
                     const char* utf16_expected_le,
-                    uint32_t hash_expected) {
+                    int32_t hash_expected) {
     uint16_t utf16_expected[length];
     for (size_t i = 0; i < length; i++) {
       uint16_t ch = (((utf16_expected_le[i*2 + 0] & 0xff) << 8) |
@@ -28,9 +28,11 @@
     }
 
     String* string = class_linker_->AllocStringFromModifiedUtf8(length, utf8_in);
-    ASSERT_EQ(length, string->count_);
+    ASSERT_EQ(length,  static_cast<size_t>(string->count_));
     ASSERT_TRUE(string->array_ != NULL);
     ASSERT_TRUE(string->array_->GetChars() != NULL);
+    // strlen is necessary because the 1-character string "\0" is interpreted as ""
+    ASSERT_TRUE(String::Equals(string, utf8_in) || length != strlen(utf8_in));
     for (size_t i = 0; i < length; i++) {
       EXPECT_EQ(utf16_expected[i], string->array_->GetChar(i));
     }
@@ -87,4 +89,23 @@
   AssertString(1, "\xef\xbf\xbf",   "\xff\xff",                 0xffff);
   AssertString(3, "h\xe1\x88\xb4i", "\x00\x68\x12\x34\x00\x69", (31 * ((31 * 0x68) + 0x1234)) + 0x69);
 }
+
+static bool StringNotEquals(const String* a, const char* b) {
+  return !String::Equals(a, b);
+}
+
+TEST_F(ObjectTest, StringEquals) {
+  String* string = class_linker_->AllocStringFromModifiedUtf8(7, "android");
+  EXPECT_PRED2(String::Equals, string, "android");
+  EXPECT_PRED2(StringNotEquals, string, "Android");
+  EXPECT_PRED2(StringNotEquals, string, "ANDROID");
+  EXPECT_PRED2(StringNotEquals, string, "");
+  EXPECT_PRED2(StringNotEquals, string, "and");
+  EXPECT_PRED2(StringNotEquals, string, "androids");
+
+  String* empty = class_linker_->AllocStringFromModifiedUtf8(0, "");
+  EXPECT_PRED2(String::Equals, empty, "");
+  EXPECT_PRED2(StringNotEquals, empty, "a");
+}
+
 }  // namespace art