Merge "String16 is moveable (noexcept)" am: 3551e457ca

Original change: https://android-review.googlesource.com/c/platform/system/core/+/1749261

Change-Id: Ia50fc76500c60ead9386f950aeb2f4369c006730
diff --git a/libutils/String16.cpp b/libutils/String16.cpp
index faf90c2..c42cada 100644
--- a/libutils/String16.cpp
+++ b/libutils/String16.cpp
@@ -96,6 +96,12 @@
     acquire();
 }
 
+String16::String16(String16&& o) noexcept
+    : mString(o.mString)
+{
+    o.mString = getEmptyString();
+}
+
 String16::String16(const String16& o, size_t len, size_t begin)
     : mString(getEmptyString())
 {
@@ -126,6 +132,13 @@
     release();
 }
 
+String16& String16::operator=(String16&& other) noexcept {
+    release();
+    mString = other.mString;
+    other.mString = getEmptyString();
+    return *this;
+}
+
 size_t String16::size() const
 {
     if (isStaticString()) {
diff --git a/libutils/String16_test.cpp b/libutils/String16_test.cpp
index 54662ac..917f1a3 100644
--- a/libutils/String16_test.cpp
+++ b/libutils/String16_test.cpp
@@ -64,6 +64,13 @@
     EXPECT_STR16EQ(u"Verify me", another);
 }
 
+TEST(String16Test, MoveAssign) {
+    String16 tmp("Verify me");
+    String16 another;
+    another = std::move(tmp);
+    EXPECT_STR16EQ(u"Verify me", another);
+}
+
 TEST(String16Test, Size) {
     String16 tmp("Verify me");
     EXPECT_EQ(9U, tmp.size());
@@ -123,6 +130,10 @@
     String16 another(std::move(tmp));
     EXPECT_STR16EQ(u"Verify me", another);
     EXPECT_TRUE(another.isStaticString());
+    // move/copy from StaticString16 is specialized (just copy the handle).
+    // no extra actions required.
+    EXPECT_STR16EQ(u"Verify me", tmp);
+    EXPECT_TRUE(tmp.isStaticString());
 }
 
 TEST(String16Test, StaticStringSize) {
@@ -174,10 +185,16 @@
     EXPECT_STR16EQ(u"Verify me", another);
 }
 
-TEST(String16Test, StringMoveFromStaticString) {
+TEST(String16Test, StringMoveAssignFromStaticString) {
     StaticString16 tmp(u"Verify me");
-    String16 another(std::move(tmp));
+    String16 another(u"nonstatic");
+    another = std::move(tmp);
     EXPECT_STR16EQ(u"Verify me", another);
+    EXPECT_TRUE(another.isStaticString());
+    // move/copy from StaticString16 is specialized (just copy handle).
+    // no extra actions required.
+    EXPECT_STR16EQ(u"Verify me", tmp);
+    EXPECT_TRUE(tmp.isStaticString());
 }
 
 TEST(String16Test, EmptyStringIsStatic) {
diff --git a/libutils/include/utils/String16.h b/libutils/include/utils/String16.h
index 60d523a..53f11fd 100644
--- a/libutils/include/utils/String16.h
+++ b/libutils/include/utils/String16.h
@@ -41,6 +41,7 @@
 public:
                                 String16();
                                 String16(const String16& o);
+                                String16(String16&& o) noexcept;
                                 String16(const String16& o,
                                          size_t len,
                                          size_t begin=0);
@@ -69,6 +70,7 @@
             status_t            append(const char16_t* other, size_t len);
 
     inline  String16&           operator=(const String16& other);
+            String16&           operator=(String16&& other) noexcept;
 
     inline  String16&           operator+=(const String16& other);
     inline  String16            operator+(const String16& other) const;
@@ -176,6 +178,12 @@
 public:
     template <size_t N>
     explicit constexpr String16(const StaticString16<N>& s) : mString(s.mString) {}
+    template <size_t N>
+    constexpr String16& operator=(const StaticString16<N>& s) {
+        release();
+        mString = s.mString;
+        return *this;
+    }
 };
 
 // String16 can be trivially moved using memcpy() because moving does not