From: Shane Carr <shane@unicode.org>
Date: Tue, 13 Feb 2018 02:28:00 +0000 (+0000)
Subject: ICU-13585 Adding std::move operators to CharString and MaybeStackArray.
X-Git-Tag: release-62-rc~200^2~119
X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=fb26c75df0162289cb278455eca0a328bcc92784;p=icu

ICU-13585 Adding std::move operators to CharString and MaybeStackArray.

X-SVN-Rev: 40904
---

diff --git a/icu4c/source/common/charstr.cpp b/icu4c/source/common/charstr.cpp
index 8bacd20ddc7..353f1d52542 100644
--- a/icu4c/source/common/charstr.cpp
+++ b/icu4c/source/common/charstr.cpp
@@ -23,6 +23,18 @@
 
 U_NAMESPACE_BEGIN
 
+CharString::CharString(CharString&& src) U_NOEXCEPT
+        : buffer(std::move(src.buffer)), len(src.len) {
+    src.len = 0;  // not strictly necessary because we make no guarantees on the source string
+}
+
+CharString& CharString::operator=(CharString&& src) U_NOEXCEPT {
+    buffer = std::move(src.buffer);
+    len = src.len;
+    src.len = 0;  // not strictly necessary because we make no guarantees on the source string
+    return *this;
+}
+
 CharString &CharString::copyFrom(const CharString &s, UErrorCode &errorCode) {
     if(U_SUCCESS(errorCode) && this!=&s && ensureCapacity(s.len+1, 0, errorCode)) {
         len=s.len;
diff --git a/icu4c/source/common/charstr.h b/icu4c/source/common/charstr.h
index 3cfdf6a897a..86f69c383a0 100644
--- a/icu4c/source/common/charstr.h
+++ b/icu4c/source/common/charstr.h
@@ -55,6 +55,18 @@ public:
     }
     ~CharString() {}
 
+    /**
+     * Move constructor; might leave src in an undefined state.
+     * This string will have the same contents and state that the source string had.
+     */
+    CharString(CharString &&src) U_NOEXCEPT;
+    /**
+     * Move assignment operator; might leave src in an undefined state.
+     * This string will have the same contents and state that the source string had.
+     * The behavior is undefined if *this and src are the same object.
+     */
+    CharString &operator=(CharString &&src) U_NOEXCEPT;
+
     /**
      * Replaces this string's contents with the other string's contents.
      * CharString does not support the standard copy constructor nor
diff --git a/icu4c/source/common/cmemory.h b/icu4c/source/common/cmemory.h
index 5cb52993abc..e3532c759e1 100644
--- a/icu4c/source/common/cmemory.h
+++ b/icu4c/source/common/cmemory.h
@@ -299,6 +299,14 @@ public:
      * Destructor deletes the array (if owned).
      */
     ~MaybeStackArray() { releaseArray(); }
+    /**
+     * Move constructor: transfers ownership or copies the stack array.
+     */
+    MaybeStackArray(MaybeStackArray<T, stackCapacity> &&src) U_NOEXCEPT;
+    /**
+     * Move assignment: transfers ownership or copies the stack array.
+     */
+    MaybeStackArray<T, stackCapacity> &operator=(MaybeStackArray<T, stackCapacity> &&src) U_NOEXCEPT;
     /**
      * Returns the array capacity (number of T items).
      * @return array capacity
@@ -376,6 +384,11 @@ private:
             uprv_free(ptr);
         }
     }
+    void resetToStackArray() {
+        ptr=stackArray;
+        capacity=stackCapacity;
+        needToRelease=FALSE;
+    }
     /* No comparison operators with other MaybeStackArray's. */
     bool operator==(const MaybeStackArray & /*other*/) {return FALSE;}
     bool operator!=(const MaybeStackArray & /*other*/) {return TRUE;}
@@ -398,6 +411,34 @@ private:
 #endif
 };
 
+template<typename T, int32_t stackCapacity>
+icu::MaybeStackArray<T, stackCapacity>::MaybeStackArray(
+        MaybeStackArray <T, stackCapacity>&& src) U_NOEXCEPT
+        : ptr(src.ptr), capacity(src.capacity), needToRelease(src.needToRelease) {
+    if (src.ptr == src.stackArray) {
+        ptr = stackArray;
+        uprv_memcpy(stackArray, src.stackArray, sizeof(T) * src.capacity);
+    } else {
+        src.resetToStackArray();  // take ownership away from src
+    }
+}
+
+template<typename T, int32_t stackCapacity>
+inline MaybeStackArray <T, stackCapacity>&
+MaybeStackArray<T, stackCapacity>::operator=(MaybeStackArray <T, stackCapacity>&& src) U_NOEXCEPT {
+    releaseArray();  // in case this instance had its own memory allocated
+    capacity = src.capacity;
+    needToRelease = src.needToRelease;
+    if (src.ptr == src.stackArray) {
+        ptr = stackArray;
+        uprv_memcpy(stackArray, src.stackArray, sizeof(T) * src.capacity);
+    } else {
+        ptr = src.ptr;
+        src.resetToStackArray();  // take ownership away from src
+    }
+    return *this;
+}
+
 template<typename T, int32_t stackCapacity>
 inline T *MaybeStackArray<T, stackCapacity>::resize(int32_t newCapacity, int32_t length) {
     if(newCapacity>0) {
@@ -447,9 +488,7 @@ inline T *MaybeStackArray<T, stackCapacity>::orphanOrClone(int32_t length, int32
         uprv_memcpy(p, ptr, (size_t)length*sizeof(T));
     }
     resultCapacity=length;
-    ptr=stackArray;
-    capacity=stackCapacity;
-    needToRelease=FALSE;
+    resetToStackArray();
     return p;
 }
 
diff --git a/icu4c/source/common/unicode/unistr.h b/icu4c/source/common/unicode/unistr.h
index b99a686126c..5920d3fdd12 100644
--- a/icu4c/source/common/unicode/unistr.h
+++ b/icu4c/source/common/unicode/unistr.h
@@ -1892,7 +1892,7 @@ public:
   UnicodeString &fastCopyFrom(const UnicodeString &src);
 
   /**
-   * Move assignment operator, might leave src in bogus state.
+   * Move assignment operator; might leave src in bogus state.
    * This string will have the same contents and state that the source string had.
    * The behavior is undefined if *this and src are the same object.
    * @param src source string
@@ -1905,7 +1905,7 @@ public:
 
   // do not use #ifndef U_HIDE_DRAFT_API for moveFrom, needed by non-draft API
   /**
-   * Move assignment, might leave src in bogus state.
+   * Move assignment; might leave src in bogus state.
    * This string will have the same contents and state that the source string had.
    * The behavior is undefined if *this and src are the same object.
    *
@@ -3350,7 +3350,7 @@ public:
   UnicodeString(const UnicodeString& that);
 
   /**
-   * Move constructor, might leave src in bogus state.
+   * Move constructor; might leave src in bogus state.
    * This string will have the same contents and state that the source string had.
    * @param src source string
    * @stable ICU 56
diff --git a/icu4c/source/test/intltest/strtest.cpp b/icu4c/source/test/intltest/strtest.cpp
index d8fd7a0042a..b95b525296e 100644
--- a/icu4c/source/test/intltest/strtest.cpp
+++ b/icu4c/source/test/intltest/strtest.cpp
@@ -551,6 +551,28 @@ StringTest::TestCharString() {
     if (chStr.length() != 0) {
         errln("%s:%d expected length() = 0, got %d", __FILE__, __LINE__, chStr.length());
     }
+
+    {
+        CharString s1("Short string", errorCode);
+        CharString s2(std::move(s1));
+        assertEquals("s2 should have content of s1", "Short string", s2.data());
+        CharString s3("Dummy", errorCode);
+        s3 = std::move(s2);
+        assertEquals("s3 should have content of s2", "Short string", s3.data());
+    }
+
+    {
+        CharString s1("Long string over 40 characters to trigger heap allocation", errorCode);
+        CharString s2(std::move(s1));
+        assertEquals("s2 should have content of s1",
+                "Long string over 40 characters to trigger heap allocation",
+                s2.data());
+        CharString s3("Dummy string with over 40 characters to trigger heap allocation", errorCode);
+        s3 = std::move(s2);
+        assertEquals("s3 should have content of s2",
+                "Long string over 40 characters to trigger heap allocation",
+                s3.data());
+    }
 }
 
 void