From: Shane Carr Date: Fri, 11 Jan 2019 21:47:33 +0000 (-0800) Subject: ICU-13800 Adding clone() on [Un]LocalizedNumber[Range]Formatter. X-Git-Tag: release-64-rc~153 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=db94f46377430eed1efd05d394117b3240450de7;p=icu ICU-13800 Adding clone() on [Un]LocalizedNumber[Range]Formatter. - Returns a LocalPointer that can be converted to std::unique_ptr. --- diff --git a/icu4c/source/i18n/number_fluent.cpp b/icu4c/source/i18n/number_fluent.cpp index 37f780c4047..5bc1f982fa6 100644 --- a/icu4c/source/i18n/number_fluent.cpp +++ b/icu4c/source/i18n/number_fluent.cpp @@ -328,6 +328,16 @@ UnicodeString NumberFormatterSettings::toSkeleton(UErrorCode& status) c return skeleton::generate(fMacros, status); } +template +LocalPointer NumberFormatterSettings::clone() const & { + return LocalPointer(new Derived(*this)); +} + +template +LocalPointer NumberFormatterSettings::clone() && { + return LocalPointer(new Derived(std::move(*this))); +} + // Declare all classes that implement NumberFormatterSettings // See https://stackoverflow.com/a/495056/1407170 template diff --git a/icu4c/source/i18n/numrange_fluent.cpp b/icu4c/source/i18n/numrange_fluent.cpp index 27ffd0b6bc5..10479f9d106 100644 --- a/icu4c/source/i18n/numrange_fluent.cpp +++ b/icu4c/source/i18n/numrange_fluent.cpp @@ -162,6 +162,16 @@ Derived NumberRangeFormatterSettings::identityFallback(UNumberRangeIden return move; } +template +LocalPointer NumberRangeFormatterSettings::clone() const & { + return LocalPointer(new Derived(*this)); +} + +template +LocalPointer NumberRangeFormatterSettings::clone() && { + return LocalPointer(new Derived(std::move(*this))); +} + // Declare all classes that implement NumberRangeFormatterSettings // See https://stackoverflow.com/a/495056/1407170 template diff --git a/icu4c/source/i18n/unicode/numberformatter.h b/icu4c/source/i18n/unicode/numberformatter.h index 611fd7e7dc2..eb3e9f86c33 100644 --- a/icu4c/source/i18n/unicode/numberformatter.h +++ b/icu4c/source/i18n/unicode/numberformatter.h @@ -44,18 +44,19 @@ * .format(1234) * .toString(); // €1.2K in en-US * - * // Create a formatter in a singleton for use later: + * // Create a formatter in a singleton by value for use later: * static const LocalizedNumberFormatter formatter = NumberFormatter::withLocale(...) * .unit(NoUnit::percent()) * .precision(Precision::fixedFraction(3)); * formatter.format(5.9831).toString(); // 5.983% in en-US * - * // Create a "template" in a singleton but without setting a locale until the call site: - * static const UnlocalizedNumberFormatter template = NumberFormatter::with() + * // Create a "template" in a singleton unique_ptr but without setting a locale until the call site: + * std::unique_ptr template = NumberFormatter::with() * .sign(UNumberSignDisplay::UNUM_SIGN_ALWAYS) * .adoptUnit(MeasureUnit::createMeter(status)) - * .unitWidth(UNumberUnitWidth::UNUM_UNIT_WIDTH_FULL_NAME); - * template.locale(...).format(1234).toString(); // +1,234 meters in en-US + * .unitWidth(UNumberUnitWidth::UNUM_UNIT_WIDTH_FULL_NAME) + * .clone(); + * template->locale(...).format(1234).toString(); // +1,234 meters in en-US * * *

@@ -2078,6 +2079,28 @@ class U_I18N_API NumberFormatterSettings { */ UnicodeString toSkeleton(UErrorCode& status) const; + /** + * Returns the current (Un)LocalizedNumberFormatter as a LocalPointer + * wrapping a heap-allocated copy of the current object. + * + * This is equivalent to new-ing the move constructor with a value object + * as the argument. + * + * @return A wrapped (Un)LocalizedNumberFormatter pointer, or a wrapped + * nullptr on failure. + * @draft ICU 64 + */ + LocalPointer clone() const &; + + /** + * Overload of clone for use on an rvalue reference. + * + * @return A wrapped (Un)LocalizedNumberFormatter pointer, or a wrapped + * nullptr on failure. + * @draft ICU 64 + */ + LocalPointer clone() &&; + /** * Sets the UErrorCode if an error occurred in the fluent chain. * Preserves older error codes in the outErrorCode. diff --git a/icu4c/source/i18n/unicode/numberrangeformatter.h b/icu4c/source/i18n/unicode/numberrangeformatter.h index dee75c6729f..3cbf290edac 100644 --- a/icu4c/source/i18n/unicode/numberrangeformatter.h +++ b/icu4c/source/i18n/unicode/numberrangeformatter.h @@ -445,6 +445,28 @@ class U_I18N_API NumberRangeFormatterSettings { */ Derived identityFallback(UNumberRangeIdentityFallback identityFallback) &&; + /** + * Returns the current (Un)LocalizedNumberRangeFormatter as a LocalPointer + * wrapping a heap-allocated copy of the current object. + * + * This is equivalent to new-ing the move constructor with a value object + * as the argument. + * + * @return A wrapped (Un)LocalizedNumberRangeFormatter pointer, or a wrapped + * nullptr on failure. + * @draft ICU 64 + */ + LocalPointer clone() const &; + + /** + * Overload of clone for use on an rvalue reference. + * + * @return A wrapped (Un)LocalizedNumberRangeFormatter pointer, or a wrapped + * nullptr on failure. + * @draft ICU 64 + */ + LocalPointer clone() &&; + /** * Sets the UErrorCode if an error occurred in the fluent chain. * Preserves older error codes in the outErrorCode. diff --git a/icu4c/source/test/intltest/numbertest.h b/icu4c/source/test/intltest/numbertest.h index 5750cecde69..9efc12da68e 100644 --- a/icu4c/source/test/intltest/numbertest.h +++ b/icu4c/source/test/intltest/numbertest.h @@ -78,6 +78,7 @@ class NumberFormatterApiTest : public IntlTestWithFieldPosition { void validRanges(); void copyMove(); void localPointerCAPI(); + void toObject(); void runIndexedTest(int32_t index, UBool exec, const char *&name, char *par = 0); @@ -270,6 +271,7 @@ class NumberRangeFormatterTest : public IntlTestWithFieldPosition { void testPlurals(); void testFieldPositions(); void testCopyMove(); + void toObject(); void runIndexedTest(int32_t index, UBool exec, const char *&name, char *par = 0); diff --git a/icu4c/source/test/intltest/numbertest_api.cpp b/icu4c/source/test/intltest/numbertest_api.cpp index 26f13ca7e05..bfa0ba23dbc 100644 --- a/icu4c/source/test/intltest/numbertest_api.cpp +++ b/icu4c/source/test/intltest/numbertest_api.cpp @@ -8,6 +8,7 @@ #include "charstr.h" #include #include +#include #include "unicode/unum.h" #include "unicode/numberformatter.h" #include "number_asformat.h" @@ -91,6 +92,7 @@ void NumberFormatterApiTest::runIndexedTest(int32_t index, UBool exec, const cha TESTCASE_AUTO(validRanges); TESTCASE_AUTO(copyMove); TESTCASE_AUTO(localPointerCAPI); + TESTCASE_AUTO(toObject); TESTCASE_AUTO_END; } @@ -2783,6 +2785,64 @@ void NumberFormatterApiTest::localPointerCAPI() { // No need to do any cleanup since we are using LocalPointer. } +void NumberFormatterApiTest::toObject() { + IcuTestErrorCode status(*this, "toObject"); + + // const lvalue version + { + LocalizedNumberFormatter lnf = NumberFormatter::withLocale("en") + .precision(Precision::fixedFraction(2)); + LocalPointer lnf2(lnf.clone()); + assertFalse("should create successfully, const lvalue", lnf2.isNull()); + assertEquals("object API test, const lvalue", u"1,000.00", + lnf2->formatDouble(1000, status).toString(status)); + } + + // rvalue reference version + { + LocalPointer lnf( + NumberFormatter::withLocale("en") + .precision(Precision::fixedFraction(2)) + .clone()); + assertFalse("should create successfully, rvalue reference", lnf.isNull()); + assertEquals("object API test, rvalue reference", u"1,000.00", + lnf->formatDouble(1000, status).toString(status)); + } + + // to std::unique_ptr via constructor + { + std::unique_ptr lnf( + NumberFormatter::withLocale("en") + .precision(Precision::fixedFraction(2)) + .clone()); + assertTrue("should create successfully, unique_ptr", static_cast(lnf)); + assertEquals("object API test, unique_ptr", u"1,000.00", + lnf->formatDouble(1000, status).toString(status)); + } + + // to std::unique_ptr via assignment + { + std::unique_ptr lnf = + NumberFormatter::withLocale("en") + .precision(Precision::fixedFraction(2)) + .clone(); + assertTrue("should create successfully, unique_ptr B", static_cast(lnf)); + assertEquals("object API test, unique_ptr B", u"1,000.00", + lnf->formatDouble(1000, status).toString(status)); + } + + // to LocalPointer via assignment + { + LocalPointer f = + NumberFormatter::with().clone(); + } + + // make sure no memory leaks + { + NumberFormatter::with().clone(); + } +} + void NumberFormatterApiTest::assertFormatDescending(const char16_t* umessage, const char16_t* uskeleton, const UnlocalizedNumberFormatter& f, Locale locale, diff --git a/icu4c/source/test/intltest/numbertest_range.cpp b/icu4c/source/test/intltest/numbertest_range.cpp index a15ef9d9b6f..75816ba9573 100644 --- a/icu4c/source/test/intltest/numbertest_range.cpp +++ b/icu4c/source/test/intltest/numbertest_range.cpp @@ -50,6 +50,7 @@ void NumberRangeFormatterTest::runIndexedTest(int32_t index, UBool exec, const c TESTCASE_AUTO(testPlurals); TESTCASE_AUTO(testFieldPositions); TESTCASE_AUTO(testCopyMove); + TESTCASE_AUTO(toObject); TESTCASE_AUTO_END; } @@ -823,6 +824,42 @@ void NumberRangeFormatterTest::testCopyMove() { assertEquals("FormattedNumberRange move assignment", u"3,00–6,00 $US", result.toString(status)); } +void NumberRangeFormatterTest::toObject() { + IcuTestErrorCode status(*this, "toObject"); + + // const lvalue version + { + LocalizedNumberRangeFormatter lnf = NumberRangeFormatter::withLocale("en"); + LocalPointer lnf2(lnf.clone()); + assertFalse("should create successfully, const lvalue", lnf2.isNull()); + assertEquals("object API test, const lvalue", u"5–7", + lnf2->formatFormattableRange(5, 7, status).toString(status)); + } + + // rvalue reference version + { + LocalPointer lnf( + NumberRangeFormatter::withLocale("en").clone()); + assertFalse("should create successfully, rvalue reference", lnf.isNull()); + assertEquals("object API test, rvalue reference", u"5–7", + lnf->formatFormattableRange(5, 7, status).toString(status)); + } + + // to std::unique_ptr via assignment + { + std::unique_ptr lnf = + NumberRangeFormatter::withLocale("en").clone(); + assertTrue("should create successfully, unique_ptr B", static_cast(lnf)); + assertEquals("object API test, unique_ptr B", u"5–7", + lnf->formatFormattableRange(5, 7, status).toString(status)); + } + + // make sure no memory leaks + { + NumberRangeFormatter::with().clone(); + } +} + void NumberRangeFormatterTest::assertFormatRange( const char16_t* message, const UnlocalizedNumberRangeFormatter& f,