diff --git a/icu4c/source/i18n/numparse_affixes.cpp b/icu4c/source/i18n/numparse_affixes.cpp index 2f317041905..66ce2bef8ca 100644 --- a/icu4c/source/i18n/numparse_affixes.cpp +++ b/icu4c/source/i18n/numparse_affixes.cpp @@ -40,16 +40,16 @@ void AffixPatternMatcherBuilder::consumeToken(AffixPatternType type, UChar32 cp, // Case 1: the token is a symbol. switch (type) { case TYPE_MINUS_SIGN: - addMatcher(fWarehouse.minusSign = {fWarehouse.dfs, true}); + addMatcher(fWarehouse.minusSign()); break; case TYPE_PLUS_SIGN: - addMatcher(fWarehouse.plusSign = {fWarehouse.dfs, true}); + addMatcher(fWarehouse.plusSign()); break; case TYPE_PERCENT: - addMatcher(fWarehouse.percent = {fWarehouse.dfs}); + addMatcher(fWarehouse.percent()); break; case TYPE_PERMILLE: - addMatcher(fWarehouse.permille = {fWarehouse.dfs}); + addMatcher(fWarehouse.permille()); break; case TYPE_CURRENCY_SINGLE: case TYPE_CURRENCY_DOUBLE: @@ -57,13 +57,7 @@ void AffixPatternMatcherBuilder::consumeToken(AffixPatternType type, UChar32 cp, case TYPE_CURRENCY_QUAD: case TYPE_CURRENCY_QUINT: // All currency symbols use the same matcher - addMatcher( - fWarehouse.currency = { - CurrencyNamesMatcher( - fWarehouse.locale, status), CurrencyCustomMatcher( - fWarehouse.currencyCode, - fWarehouse.currency1, - fWarehouse.currency2)}); + addMatcher(fWarehouse.currency(status)); break; default: U_ASSERT(FALSE); @@ -109,12 +103,32 @@ AffixTokenMatcherWarehouse::AffixTokenMatcherWarehouse(const UChar* currencyCode AffixTokenMatcherWarehouse::~AffixTokenMatcherWarehouse() { // Delete the variable number of batches of code point matchers - for (int32_t i=0; i codePointsOverflow; // On heap in "batches" diff --git a/icu4c/source/i18n/numparse_compositions.cpp b/icu4c/source/i18n/numparse_compositions.cpp index 138b45c6dac..6d8d52d2ba5 100644 --- a/icu4c/source/i18n/numparse_compositions.cpp +++ b/icu4c/source/i18n/numparse_compositions.cpp @@ -19,7 +19,7 @@ bool AnyMatcher::match(StringSegment& segment, ParsedNumber& result, UErrorCode& bool maybeMore = false; // NOTE: The range-based for loop calls the virtual begin() and end() methods. - for (auto* matcher : *this) { + for (auto& matcher : *this) { maybeMore = maybeMore || matcher->match(segment, result, status); if (segment.getOffset() != initialOffset) { // Match succeeded. diff --git a/icu4c/source/i18n/numparse_currency.cpp b/icu4c/source/i18n/numparse_currency.cpp index 1cd730214af..cf56a94f6d2 100644 --- a/icu4c/source/i18n/numparse_currency.cpp +++ b/icu4c/source/i18n/numparse_currency.cpp @@ -119,6 +119,19 @@ CurrencyAnyMatcher::CurrencyAnyMatcher(CurrencyNamesMatcher namesMatcher, fMatcherArray[1] = &fCustomMatcher; } +CurrencyAnyMatcher::CurrencyAnyMatcher(CurrencyAnyMatcher&& src) U_NOEXCEPT + : fNamesMatcher(std::move(src.fNamesMatcher)), fCustomMatcher(std::move(src.fCustomMatcher)) { + fMatcherArray[0] = &fNamesMatcher; + fMatcherArray[1] = &fCustomMatcher; +} + +CurrencyAnyMatcher& CurrencyAnyMatcher::operator=(CurrencyAnyMatcher&& src) U_NOEXCEPT { + fNamesMatcher = std::move(src.fNamesMatcher); + fCustomMatcher = std::move(src.fCustomMatcher); + // Note: do NOT move fMatcherArray + return *this; +} + const UnicodeSet& CurrencyAnyMatcher::getLeadCodePoints() { if (fLocalLeadCodePoints.isNull()) { auto* leadCodePoints = new UnicodeSet(); diff --git a/icu4c/source/i18n/numparse_currency.h b/icu4c/source/i18n/numparse_currency.h index bbfa15094a8..547f6ee0417 100644 --- a/icu4c/source/i18n/numparse_currency.h +++ b/icu4c/source/i18n/numparse_currency.h @@ -67,6 +67,12 @@ class CurrencyAnyMatcher : public AnyMatcher, public UMemory { CurrencyAnyMatcher(CurrencyNamesMatcher namesMatcher, CurrencyCustomMatcher customMatcher); + // Needs custom move constructor/operator since constructor is nontrivial + + CurrencyAnyMatcher(CurrencyAnyMatcher&& src) U_NOEXCEPT; + + CurrencyAnyMatcher& operator=(CurrencyAnyMatcher&& src) U_NOEXCEPT; + const UnicodeSet& getLeadCodePoints() override; protected: diff --git a/icu4c/source/test/intltest/numbertest_parse.cpp b/icu4c/source/test/intltest/numbertest_parse.cpp index 78492aa391e..9cb8dd12d4a 100644 --- a/icu4c/source/test/intltest/numbertest_parse.cpp +++ b/icu4c/source/test/intltest/numbertest_parse.cpp @@ -23,6 +23,7 @@ void NumberParserTest::runIndexedTest(int32_t index, UBool exec, const char*& na TESTCASE_AUTO_BEGIN; TESTCASE_AUTO(testBasic); TESTCASE_AUTO(testSeriesMatcher); + TESTCASE_AUTO(testCurrencyAnyMatcher); TESTCASE_AUTO(testAffixPatternMatcher); TESTCASE_AUTO_END; } @@ -211,6 +212,39 @@ void NumberParserTest::testSeriesMatcher() { } } +void NumberParserTest::testCurrencyAnyMatcher() { + IcuTestErrorCode status(*this, "testCurrencyAnyMatcher"); + + IgnorablesMatcher ignorables(unisets::DEFAULT_IGNORABLES); + AffixTokenMatcherWarehouse warehouse(u"ICU", u"IU$", u"ICU", {"en",status}, &ignorables, "en"); + NumberParseMatcher& matcher = warehouse.currency(status); + + static const struct TestCase{ + const char16_t* input; + const char16_t* expectedCurrencyCode; + } cases[] { + { u"", u"\x00" }, + { u"FOO", u"\x00" }, + { u"USD", u"USD" }, + { u"$", u"USD" }, + { u"US dollars", u"USD" }, + { u"eu", u"\x00" }, + { u"euros", u"EUR" }, + { u"ICU", u"ICU" }, + { u"IU$", u"ICU" } }; + for (auto& cas : cases) { + UnicodeString input(cas.input); + + StringSegment segment(input, 0); + ParsedNumber result; + matcher.match(segment, result, status); + assertEquals("Parsing " + input, cas.expectedCurrencyCode, result.currencyCode); + assertEquals("Whole string on " + input, + cas.expectedCurrencyCode[0] == 0 ? 0 : input.length(), + result.charEnd); + } +} + void NumberParserTest::testAffixPatternMatcher() { IcuTestErrorCode status(*this, "testAffixPatternMatcher"); @@ -227,7 +261,7 @@ void NumberParserTest::testAffixPatternMatcher() { {true, u"+-%", 3, u"+-%"}, {false, u"ab c", 5, u"a bc"}, {true, u"abc", 3, u"abc"}, - //{false, u"hello-to+this%very¤long‰string", 59, u"hello-to+this%very USD long‰string"} + {false, u"hello-to+this%very¤long‰string", 59, u"hello-to+this%very USD long‰string"} }; for (auto& cas : cases) {