]> git.saurik.com Git - apple/icu.git/blobdiff - icuSources/i18n/number_patternmodifier.cpp
ICU-64243.0.1.tar.gz
[apple/icu.git] / icuSources / i18n / number_patternmodifier.cpp
index 6417e14378bea66e80e7705b22bfde1417965dae..75de439f3ed2e16ec5dfccb572c0892075f07547 100644 (file)
@@ -23,33 +23,34 @@ AffixPatternProvider::~AffixPatternProvider() = default;
 MutablePatternModifier::MutablePatternModifier(bool isStrong)
         : fStrong(isStrong) {}
 
-void MutablePatternModifier::setPatternInfo(const AffixPatternProvider* patternInfo) {
-    this->patternInfo = patternInfo;
+void MutablePatternModifier::setPatternInfo(const AffixPatternProvider* patternInfo, Field field) {
+    fPatternInfo = patternInfo;
+    fField = field;
 }
 
 void MutablePatternModifier::setPatternAttributes(UNumberSignDisplay signDisplay, bool perMille) {
-    this->signDisplay = signDisplay;
-    this->perMilleReplacesPercent = perMille;
+    fSignDisplay = signDisplay;
+    fPerMilleReplacesPercent = perMille;
 }
 
 void MutablePatternModifier::setSymbols(const DecimalFormatSymbols* symbols,
                                         const CurrencySymbols* currencySymbols,
                                         const UNumberUnitWidth unitWidth, const PluralRules* rules) {
     U_ASSERT((rules != nullptr) == needsPlurals());
-    this->symbols = symbols;
-    this->currencySymbols = currencySymbols;
-    this->unitWidth = unitWidth;
-    this->rules = rules;
+    fSymbols = symbols;
+    fCurrencySymbols = currencySymbols;
+    fUnitWidth = unitWidth;
+    fRules = rules;
 }
 
 void MutablePatternModifier::setNumberProperties(int8_t signum, StandardPlural::Form plural) {
-    this->signum = signum;
-    this->plural = plural;
+    fSignum = signum;
+    fPlural = plural;
 }
 
 bool MutablePatternModifier::needsPlurals() const {
     UErrorCode statusLocal = U_ZERO_ERROR;
-    return patternInfo->containsSymbolType(AffixPatternType::TYPE_CURRENCY_TRIPLE, statusLocal);
+    return fPatternInfo->containsSymbolType(AffixPatternType::TYPE_CURRENCY_TRIPLE, statusLocal);
     // Silently ignore any error codes.
 }
 
@@ -69,7 +70,7 @@ MutablePatternModifier::createImmutableAndChain(const MicroPropsGenerator* paren
             StandardPlural::Form::MANY,
             StandardPlural::Form::OTHER};
 
-    auto pm = new ParameterizedModifier();
+    auto pm = new AdoptingModifierStore();
     if (pm == nullptr) {
         status = U_MEMORY_ALLOCATION_ERROR;
         return nullptr;
@@ -79,26 +80,25 @@ MutablePatternModifier::createImmutableAndChain(const MicroPropsGenerator* paren
         // Slower path when we require the plural keyword.
         for (StandardPlural::Form plural : STANDARD_PLURAL_VALUES) {
             setNumberProperties(1, plural);
-            pm->adoptSignPluralModifier(1, plural, createConstantModifier(status));
+            pm->adoptModifier(1, plural, createConstantModifier(status));
             setNumberProperties(0, plural);
-            pm->adoptSignPluralModifier(0, plural, createConstantModifier(status));
+            pm->adoptModifier(0, plural, createConstantModifier(status));
             setNumberProperties(-1, plural);
-            pm->adoptSignPluralModifier(-1, plural, createConstantModifier(status));
+            pm->adoptModifier(-1, plural, createConstantModifier(status));
         }
         if (U_FAILURE(status)) {
             delete pm;
             return nullptr;
         }
-        return new ImmutablePatternModifier(pm, rules, parent);  // adopts pm
+        return new ImmutablePatternModifier(pm, fRules, parent);  // adopts pm
     } else {
         // Faster path when plural keyword is not needed.
         setNumberProperties(1, StandardPlural::Form::COUNT);
-        Modifier* positive = createConstantModifier(status);
+        pm->adoptModifierWithoutPlural(1, createConstantModifier(status));
         setNumberProperties(0, StandardPlural::Form::COUNT);
-        Modifier* zero = createConstantModifier(status);
+        pm->adoptModifierWithoutPlural(0, createConstantModifier(status));
         setNumberProperties(-1, StandardPlural::Form::COUNT);
-        Modifier* negative = createConstantModifier(status);
-        pm->adoptPositiveNegativeModifiers(positive, zero, negative);
+        pm->adoptModifierWithoutPlural(-1, createConstantModifier(status));
         if (U_FAILURE(status)) {
             delete pm;
             return nullptr;
@@ -112,39 +112,37 @@ ConstantMultiFieldModifier* MutablePatternModifier::createConstantModifier(UErro
     NumberStringBuilder b;
     insertPrefix(a, 0, status);
     insertSuffix(b, 0, status);
-    if (patternInfo->hasCurrencySign()) {
+    if (fPatternInfo->hasCurrencySign()) {
         return new CurrencySpacingEnabledModifier(
-                a, b, !patternInfo->hasBody(), fStrong, *symbols, status);
+                a, b, !fPatternInfo->hasBody(), fStrong, *fSymbols, status);
     } else {
-        return new ConstantMultiFieldModifier(a, b, !patternInfo->hasBody(), fStrong);
+        return new ConstantMultiFieldModifier(a, b, !fPatternInfo->hasBody(), fStrong);
     }
 }
 
-ImmutablePatternModifier::ImmutablePatternModifier(ParameterizedModifier* pm, const PluralRules* rules,
+ImmutablePatternModifier::ImmutablePatternModifier(AdoptingModifierStore* pm, const PluralRules* rules,
                                                    const MicroPropsGenerator* parent)
         : pm(pm), rules(rules), parent(parent) {}
 
 void ImmutablePatternModifier::processQuantity(DecimalQuantity& quantity, MicroProps& micros,
                                                UErrorCode& status) const {
     parent->processQuantity(quantity, micros, status);
-    applyToMicros(micros, quantity);
+    applyToMicros(micros, quantity, status);
 }
 
-void ImmutablePatternModifier::applyToMicros(MicroProps& micros, DecimalQuantity& quantity) const {
+void ImmutablePatternModifier::applyToMicros(
+        MicroProps& micros, const DecimalQuantity& quantity, UErrorCode& status) const {
     if (rules == nullptr) {
-        micros.modMiddle = pm->getModifier(quantity.signum());
+        micros.modMiddle = pm->getModifierWithoutPlural(quantity.signum());
     } else {
-        // TODO: Fix this. Avoid the copy.
-        DecimalQuantity copy(quantity);
-        copy.roundToInfinity();
-        StandardPlural::Form plural = utils::getStandardPlural(rules, copy);
-        micros.modMiddle = pm->getModifier(quantity.signum(), plural);
+        StandardPlural::Form pluralForm = utils::getPluralSafe(micros.rounder, rules, quantity, status);
+        micros.modMiddle = pm->getModifier(quantity.signum(), pluralForm);
     }
 }
 
 const Modifier* ImmutablePatternModifier::getModifier(int8_t signum, StandardPlural::Form plural) const {
     if (rules == nullptr) {
-        return pm->getModifier(signum);
+        return pm->getModifierWithoutPlural(signum);
     } else {
         return pm->getModifier(signum, plural);
     }
@@ -153,21 +151,19 @@ const Modifier* ImmutablePatternModifier::getModifier(int8_t signum, StandardPlu
 
 /** Used by the unsafe code path. */
 MicroPropsGenerator& MutablePatternModifier::addToChain(const MicroPropsGenerator* parent) {
-    this->parent = parent;
+    fParent = parent;
     return *this;
 }
 
 void MutablePatternModifier::processQuantity(DecimalQuantity& fq, MicroProps& micros,
                                              UErrorCode& status) const {
-    parent->processQuantity(fq, micros, status);
+    fParent->processQuantity(fq, micros, status);
     // The unsafe code path performs self-mutation, so we need a const_cast.
     // This method needs to be const because it overrides a const method in the parent class.
     auto nonConstThis = const_cast<MutablePatternModifier*>(this);
     if (needsPlurals()) {
-        // TODO: Fix this. Avoid the copy.
-        DecimalQuantity copy(fq);
-        micros.rounder.apply(copy, status);
-        nonConstThis->setNumberProperties(fq.signum(), utils::getStandardPlural(rules, copy));
+        StandardPlural::Form pluralForm = utils::getPluralSafe(micros.rounder, fRules, fq, status);
+        nonConstThis->setNumberProperties(fq.signum(), pluralForm);
     } else {
         nonConstThis->setNumberProperties(fq.signum(), StandardPlural::Form::COUNT);
     }
@@ -183,7 +179,7 @@ int32_t MutablePatternModifier::apply(NumberStringBuilder& output, int32_t leftI
     int32_t suffixLen = nonConstThis->insertSuffix(output, rightIndex + prefixLen, status);
     // If the pattern had no decimal stem body (like #,##0.00), overwrite the value.
     int32_t overwriteLen = 0;
-    if (!patternInfo->hasBody()) {
+    if (!fPatternInfo->hasBody()) {
         overwriteLen = output.splice(
                 leftIndex + prefixLen,
                 rightIndex + prefixLen,
@@ -199,28 +195,30 @@ int32_t MutablePatternModifier::apply(NumberStringBuilder& output, int32_t leftI
             prefixLen,
             rightIndex + overwriteLen + prefixLen,
             suffixLen,
-            *symbols,
+            *fSymbols,
             status);
     return prefixLen + overwriteLen + suffixLen;
 }
 
-int32_t MutablePatternModifier::getPrefixLength(UErrorCode& status) const {
+int32_t MutablePatternModifier::getPrefixLength() const {
     // The unsafe code path performs self-mutation, so we need a const_cast.
     // This method needs to be const because it overrides a const method in the parent class.
     auto nonConstThis = const_cast<MutablePatternModifier*>(this);
 
     // Enter and exit CharSequence Mode to get the length.
+    UErrorCode status = U_ZERO_ERROR; // status fails only with an iilegal argument exception
     nonConstThis->prepareAffix(true);
     int result = AffixUtils::unescapedCodePointCount(currentAffix, *this, status);  // prefix length
     return result;
 }
 
-int32_t MutablePatternModifier::getCodePointCount(UErrorCode& status) const {
+int32_t MutablePatternModifier::getCodePointCount() const {
     // The unsafe code path performs self-mutation, so we need a const_cast.
     // This method needs to be const because it overrides a const method in the parent class.
     auto nonConstThis = const_cast<MutablePatternModifier*>(this);
 
     // Render the affixes to get the length
+    UErrorCode status = U_ZERO_ERROR; // status fails only with an iilegal argument exception
     nonConstThis->prepareAffix(true);
     int result = AffixUtils::unescapedCodePointCount(currentAffix, *this, status);  // prefix length
     nonConstThis->prepareAffix(false);
@@ -232,69 +230,85 @@ bool MutablePatternModifier::isStrong() const {
     return fStrong;
 }
 
+bool MutablePatternModifier::containsField(UNumberFormatFields field) const {
+    (void)field;
+    // This method is not currently used.
+    UPRV_UNREACHABLE;
+}
+
+void MutablePatternModifier::getParameters(Parameters& output) const {
+    (void)output;
+    // This method is not currently used.
+    UPRV_UNREACHABLE;
+}
+
+bool MutablePatternModifier::semanticallyEquivalent(const Modifier& other) const {
+    (void)other;
+    // This method is not currently used.
+    UPRV_UNREACHABLE;
+}
+
 int32_t MutablePatternModifier::insertPrefix(NumberStringBuilder& sb, int position, UErrorCode& status) {
     prepareAffix(true);
-    int length = AffixUtils::unescape(currentAffix, sb, position, *this, status);
+    int32_t length = AffixUtils::unescape(currentAffix, sb, position, *this, fField, status);
     return length;
 }
 
 int32_t MutablePatternModifier::insertSuffix(NumberStringBuilder& sb, int position, UErrorCode& status) {
     prepareAffix(false);
-    int length = AffixUtils::unescape(currentAffix, sb, position, *this, status);
+    int32_t length = AffixUtils::unescape(currentAffix, sb, position, *this, fField, status);
     return length;
 }
 
 /** This method contains the heart of the logic for rendering LDML affix strings. */
 void MutablePatternModifier::prepareAffix(bool isPrefix) {
     PatternStringUtils::patternInfoToStringBuilder(
-            *patternInfo, isPrefix, signum, signDisplay, plural, perMilleReplacesPercent, currentAffix);
+            *fPatternInfo, isPrefix, fSignum, fSignDisplay, fPlural, fPerMilleReplacesPercent, currentAffix);
 }
 
 UnicodeString MutablePatternModifier::getSymbol(AffixPatternType type) const {
     UErrorCode localStatus = U_ZERO_ERROR;
     switch (type) {
         case AffixPatternType::TYPE_MINUS_SIGN:
-            return symbols->getSymbol(DecimalFormatSymbols::ENumberFormatSymbol::kMinusSignSymbol);
+            return fSymbols->getSymbol(DecimalFormatSymbols::ENumberFormatSymbol::kMinusSignSymbol);
         case AffixPatternType::TYPE_PLUS_SIGN:
-            return symbols->getSymbol(DecimalFormatSymbols::ENumberFormatSymbol::kPlusSignSymbol);
+            return fSymbols->getSymbol(DecimalFormatSymbols::ENumberFormatSymbol::kPlusSignSymbol);
         case AffixPatternType::TYPE_PERCENT:
-            return symbols->getSymbol(DecimalFormatSymbols::ENumberFormatSymbol::kPercentSymbol);
+            return fSymbols->getSymbol(DecimalFormatSymbols::ENumberFormatSymbol::kPercentSymbol);
         case AffixPatternType::TYPE_PERMILLE:
-            return symbols->getSymbol(DecimalFormatSymbols::ENumberFormatSymbol::kPerMillSymbol);
+            return fSymbols->getSymbol(DecimalFormatSymbols::ENumberFormatSymbol::kPerMillSymbol);
         case AffixPatternType::TYPE_CURRENCY_SINGLE: {
             // UnitWidth ISO and HIDDEN overrides the singular currency symbol.
-            if (unitWidth == UNumberUnitWidth::UNUM_UNIT_WIDTH_ISO_CODE) {
-                return currencySymbols->getIntlCurrencySymbol(localStatus);
-            } else if (unitWidth == UNumberUnitWidth::UNUM_UNIT_WIDTH_HIDDEN) {
+            if (fUnitWidth == UNumberUnitWidth::UNUM_UNIT_WIDTH_ISO_CODE) {
+                return fCurrencySymbols->getIntlCurrencySymbol(localStatus);
+            } else if (fUnitWidth == UNumberUnitWidth::UNUM_UNIT_WIDTH_HIDDEN) {
                 return UnicodeString();
-            } else if (unitWidth == UNumberUnitWidth::UNUM_UNIT_WIDTH_NARROW) {
-                return currencySymbols->getNarrowCurrencySymbol(localStatus);
+            } else if (fUnitWidth == UNumberUnitWidth::UNUM_UNIT_WIDTH_NARROW) {
+                return fCurrencySymbols->getNarrowCurrencySymbol(localStatus);
             } else {
-                return currencySymbols->getCurrencySymbol(localStatus);
+                return fCurrencySymbols->getCurrencySymbol(localStatus);
             }
         }
         case AffixPatternType::TYPE_CURRENCY_DOUBLE:
-            return currencySymbols->getIntlCurrencySymbol(localStatus);
+            return fCurrencySymbols->getIntlCurrencySymbol(localStatus);
         case AffixPatternType::TYPE_CURRENCY_TRIPLE:
             // NOTE: This is the code path only for patterns containing "¤¤¤".
             // Plural currencies set via the API are formatted in LongNameHandler.
             // This code path is used by DecimalFormat via CurrencyPluralInfo.
-            U_ASSERT(plural != StandardPlural::Form::COUNT);
-            return currencySymbols->getPluralName(plural, localStatus);
+            U_ASSERT(fPlural != StandardPlural::Form::COUNT);
+            return fCurrencySymbols->getPluralName(fPlural, localStatus);
         case AffixPatternType::TYPE_CURRENCY_QUAD:
             return UnicodeString(u"\uFFFD");
         case AffixPatternType::TYPE_CURRENCY_QUINT:
             return UnicodeString(u"\uFFFD");
         default:
-            U_ASSERT(false);
-            return UnicodeString();
+            UPRV_UNREACHABLE;
     }
 }
 
 UnicodeString MutablePatternModifier::toUnicodeString() const {
     // Never called by AffixUtils
-    U_ASSERT(false);
-    return UnicodeString();
+    UPRV_UNREACHABLE;
 }
 
 #endif /* #if !UCONFIG_NO_FORMATTING */