From b7a3571b2175895f56873ea54fff432a55e46359 Mon Sep 17 00:00:00 2001 From: Shane Carr Date: Thu, 24 Jan 2019 16:13:04 -0800 Subject: [PATCH] ICU-20357 Adding LocalPointer conversion methods to/from std::unique_ptr - Requires the right side to be an rvalue reference. - Includes move constructor, move operator, and conversion operator. --- icu4c/source/common/unicode/localpointer.h | 76 ++++++++++++++++++++++ icu4c/source/test/intltest/itutil.cpp | 26 ++++++++ 2 files changed, 102 insertions(+) diff --git a/icu4c/source/common/unicode/localpointer.h b/icu4c/source/common/unicode/localpointer.h index 9ed874b706a..8872e05d004 100644 --- a/icu4c/source/common/unicode/localpointer.h +++ b/icu4c/source/common/unicode/localpointer.h @@ -42,6 +42,8 @@ #if U_SHOW_CPLUSPLUS_API +#include + U_NAMESPACE_BEGIN /** @@ -222,6 +224,17 @@ public: LocalPointer(LocalPointer &&src) U_NOEXCEPT : LocalPointerBase(src.ptr) { src.ptr=NULL; } + /** + * Constructs a LocalPointer from a C++11 std::unique_ptr. + * The LocalPointer steals the object owned by the std::unique_ptr. + * + * This constructor works via move semantics. If your std::unique_ptr is + * in a local variable, you must use std::move. + * + * @param p The std::unique_ptr from which the pointer will be stolen. + * @draft ICU 64 + */ + explicit LocalPointer(std::unique_ptr &&p) : LocalPointerBase(p.release()) {} /** * Destructor deletes the object it owns. * @stable ICU 4.4 @@ -239,6 +252,18 @@ public: LocalPointer &operator=(LocalPointer &&src) U_NOEXCEPT { return moveFrom(src); } + /** + * Move-assign from an std::unique_ptr to this LocalPointer. + * Steals the pointer from the std::unique_ptr. + * + * @param p The std::unique_ptr from which the pointer will be stolen. + * @return *this + * @draft ICU 64 + */ + LocalPointer &operator=(std::unique_ptr &&p) U_NOEXCEPT { + adoptInstead(p.release()); + return *this; + } // do not use #ifndef U_HIDE_DRAFT_API for moveFrom, needed by non-draft API /** * Move assignment, leaves src with isNull(). @@ -310,6 +335,20 @@ public: delete p; } } + /** + * Conversion operator to a C++11 std::unique_ptr. + * Disowns the object and gives it to the returned std::unique_ptr. + * + * This operator works via move semantics. If your LocalPointer is + * in a local variable, you must use std::move. + * + * @return An std::unique_ptr owning the pointer previously owned by this + * icu::LocalPointer. + * @draft ICU 64 + */ + operator std::unique_ptr () && { + return std::unique_ptr(LocalPointerBase::orphan()); + } }; /** @@ -367,6 +406,17 @@ public: LocalArray(LocalArray &&src) U_NOEXCEPT : LocalPointerBase(src.ptr) { src.ptr=NULL; } + /** + * Constructs a LocalArray from a C++11 std::unique_ptr of an array type. + * The LocalPointer steals the array owned by the std::unique_ptr. + * + * This constructor works via move semantics. If your std::unique_ptr is + * in a local variable, you must use std::move. + * + * @param p The std::unique_ptr from which the array will be stolen. + * @draft ICU 64 + */ + explicit LocalArray(std::unique_ptr &&p) : LocalPointerBase(p.release()) {} /** * Destructor deletes the array it owns. * @stable ICU 4.4 @@ -384,6 +434,18 @@ public: LocalArray &operator=(LocalArray &&src) U_NOEXCEPT { return moveFrom(src); } + /** + * Move-assign from an std::unique_ptr to this LocalPointer. + * Steals the array from the std::unique_ptr. + * + * @param p The std::unique_ptr from which the array will be stolen. + * @return *this + * @draft ICU 64 + */ + LocalArray &operator=(std::unique_ptr &&p) U_NOEXCEPT { + adoptInstead(p.release()); + return *this; + } // do not use #ifndef U_HIDE_DRAFT_API for moveFrom, needed by non-draft API /** * Move assignment, leaves src with isNull(). @@ -463,6 +525,20 @@ public: * @stable ICU 4.4 */ T &operator[](ptrdiff_t i) const { return LocalPointerBase::ptr[i]; } + /** + * Conversion operator to a C++11 std::unique_ptr. + * Disowns the object and gives it to the returned std::unique_ptr. + * + * This operator works via move semantics. If your LocalPointer is + * in a local variable, you must use std::move. + * + * @return An std::unique_ptr owning the pointer previously owned by this + * icu::LocalPointer. + * @draft ICU 64 + */ + operator std::unique_ptr () && { + return std::unique_ptr(LocalPointerBase::orphan()); + } }; /** diff --git a/icu4c/source/test/intltest/itutil.cpp b/icu4c/source/test/intltest/itutil.cpp index cd1935ab0ec..038028b30e5 100644 --- a/icu4c/source/test/intltest/itutil.cpp +++ b/icu4c/source/test/intltest/itutil.cpp @@ -385,8 +385,10 @@ public: void TestLocalPointer(); void TestLocalPointerMoveSwap(); + void TestLocalPointerStdUniquePtr(); void TestLocalArray(); void TestLocalArrayMoveSwap(); + void TestLocalArrayStdUniquePtr(); void TestLocalXyzPointer(); void TestLocalXyzPointerMoveSwap(); void TestLocalXyzPointerNull(); @@ -403,8 +405,10 @@ void LocalPointerTest::runIndexedTest(int32_t index, UBool exec, const char *&na TESTCASE_AUTO_BEGIN; TESTCASE_AUTO(TestLocalPointer); TESTCASE_AUTO(TestLocalPointerMoveSwap); + TESTCASE_AUTO(TestLocalPointerStdUniquePtr); TESTCASE_AUTO(TestLocalArray); TESTCASE_AUTO(TestLocalArrayMoveSwap); + TESTCASE_AUTO(TestLocalArrayStdUniquePtr); TESTCASE_AUTO(TestLocalXyzPointer); TESTCASE_AUTO(TestLocalXyzPointerMoveSwap); TESTCASE_AUTO(TestLocalXyzPointerNull); @@ -514,6 +518,17 @@ void LocalPointerTest::TestLocalPointerMoveSwap() { s3.moveFrom(s3); } +void LocalPointerTest::TestLocalPointerStdUniquePtr() { + // Implicit conversion operator + std::unique_ptr s = LocalPointer(new UnicodeString((UChar32)0x50005)); + // Explicit move constructor + LocalPointer s2(std::move(s)); + // Conversion operator should also work with std::move + s = std::move(s2); + // Back again with move assignment + s2 = std::move(s); +} + // Exercise almost every LocalArray method (but not LocalPointerBase). void LocalPointerTest::TestLocalArray() { // constructor @@ -607,6 +622,17 @@ void LocalPointerTest::TestLocalArrayMoveSwap() { a3.moveFrom(a3); } +void LocalPointerTest::TestLocalArrayStdUniquePtr() { + // Implicit conversion operator + std::unique_ptr a = LocalArray(new UnicodeString[2]); + // Explicit move constructor + LocalArray a2(std::move(a)); + // Conversion operator should also work with std::move + a = std::move(a2); + // Back again with move assignment + a2 = std::move(a); +} + #include "unicode/ucnvsel.h" #include "unicode/ucal.h" #include "unicode/udatpg.h"