]> granicus.if.org Git - icu/commitdiff
ICU-11276 Rewriring NumberFormatterImpl to expose information needed for NumberRangeF...
authorShane Carr <shane@unicode.org>
Wed, 5 Sep 2018 22:23:36 +0000 (15:23 -0700)
committerShane Carr <shane@unicode.org>
Thu, 27 Sep 2018 21:27:39 +0000 (14:27 -0700)
icu4c/source/i18n/number_fluent.cpp
icu4c/source/i18n/number_formatimpl.cpp
icu4c/source/i18n/number_formatimpl.h

index 06b10fd27651ab15f9838f31c7adc284e1990491..cc2431cf72c7c9e558cb03028d419aa75cf4cf62 100644 (file)
@@ -657,9 +657,9 @@ LocalizedNumberFormatter::formatDecimalQuantity(const DecimalQuantity& dq, UErro
 
 void LocalizedNumberFormatter::formatImpl(impl::UFormattedNumberData* results, UErrorCode& status) const {
     if (computeCompiled(status)) {
-        fCompiled->apply(results->quantity, results->string, status);
+        fCompiled->format(results->quantity, results->string, status);
     } else {
-        NumberFormatterImpl::applyStatic(fMacros, results->quantity, results->string, status);
+        NumberFormatterImpl::formatStatic(fMacros, results->quantity, results->string, status);
     }
 }
 
index 3f887128bcc668cec2a3f8a79a1cc067eea7631b..b60ba4fb97d0f472ea25991af99371257cef8640 100644 (file)
@@ -71,10 +71,13 @@ NumberFormatterImpl* NumberFormatterImpl::fromMacros(const MacroProps& macros, U
     return new NumberFormatterImpl(macros, true, status);
 }
 
-void NumberFormatterImpl::applyStatic(const MacroProps& macros, DecimalQuantity& inValue,
-                                      NumberStringBuilder& outString, UErrorCode& status) {
+void NumberFormatterImpl::formatStatic(const MacroProps& macros, DecimalQuantity& inValue,
+                                       NumberStringBuilder& outString, UErrorCode& status) {
     NumberFormatterImpl impl(macros, false, status);
-    impl.applyUnsafe(inValue, outString, status);
+    MicroProps& micros = impl.preProcessUnsafe(inValue, status);
+    if (U_FAILURE(status)) { return; }
+    int32_t length = formatNumber(micros, inValue, outString, 0, status);
+    writeAffixes(micros, outString, 0, length, status);
 }
 
 int32_t NumberFormatterImpl::getPrefixSuffixStatic(const MacroProps& macros, int8_t signum,
@@ -89,22 +92,35 @@ int32_t NumberFormatterImpl::getPrefixSuffixStatic(const MacroProps& macros, int
 // The "unsafe" method simply re-uses fMicros, eliminating the extra copy operation.
 // See MicroProps::processQuantity() for details.
 
-void NumberFormatterImpl::apply(DecimalQuantity& inValue, NumberStringBuilder& outString,
+void NumberFormatterImpl::format(DecimalQuantity& inValue, NumberStringBuilder& outString,
                                 UErrorCode& status) const {
-    if (U_FAILURE(status)) { return; }
     MicroProps micros;
-    if (!fMicroPropsGenerator) { return; }
-    fMicroPropsGenerator->processQuantity(inValue, micros, status);
+    preProcess(inValue, micros, status);
     if (U_FAILURE(status)) { return; }
-    microsToString(micros, inValue, outString, status);
+    int32_t length = formatNumber(micros, inValue, outString, 0, status);
+    writeAffixes(micros, outString, 0, length, status);
 }
 
-void NumberFormatterImpl::applyUnsafe(DecimalQuantity& inValue, NumberStringBuilder& outString,
-                                      UErrorCode& status) {
+void NumberFormatterImpl::preProcess(DecimalQuantity& inValue, MicroProps& microsOut,
+                                     UErrorCode& status) const {
     if (U_FAILURE(status)) { return; }
+    if (fMicroPropsGenerator == nullptr) {
+        status = U_INTERNAL_PROGRAM_ERROR;
+        return;
+    }
+    fMicroPropsGenerator->processQuantity(inValue, microsOut, status);
+}
+
+MicroProps& NumberFormatterImpl::preProcessUnsafe(DecimalQuantity& inValue, UErrorCode& status) {
+    if (U_FAILURE(status)) {
+        return fMicros; // must always return a value
+    }
+    if (fMicroPropsGenerator == nullptr) {
+        status = U_INTERNAL_PROGRAM_ERROR;
+        return fMicros; // must always return a value
+    }
     fMicroPropsGenerator->processQuantity(inValue, fMicros, status);
-    if (U_FAILURE(status)) { return; }
-    microsToString(fMicros, inValue, outString, status);
+    return fMicros;
 }
 
 int32_t NumberFormatterImpl::getPrefixSuffix(int8_t signum, StandardPlural::Form plural,
@@ -404,50 +420,55 @@ NumberFormatterImpl::resolvePluralRules(const PluralRules* rulesPtr, const Local
     return fRules.getAlias();
 }
 
-int32_t NumberFormatterImpl::microsToString(const MicroProps& micros, DecimalQuantity& quantity,
-                                            NumberStringBuilder& string, UErrorCode& status) {
+int32_t NumberFormatterImpl::formatNumber(const MicroProps& micros, DecimalQuantity& quantity,
+                                          NumberStringBuilder& string, int32_t index,
+                                          UErrorCode& status) {
     micros.rounder.apply(quantity, status);
     micros.integerWidth.apply(quantity, status);
-    int32_t length = writeNumber(micros, quantity, string, status);
-    // NOTE: When range formatting is added, these modifiers can bubble up.
-    // For now, apply them all here at once.
+    int32_t length = writeNumber(micros, quantity, string, index, status);
+    return length;
+}
+
+int32_t NumberFormatterImpl::writeAffixes(const MicroProps& micros, NumberStringBuilder& string,
+                                          int32_t start, int32_t end, UErrorCode& status) {
     // Always apply the inner modifier (which is "strong").
-    length += micros.modInner->apply(string, 0, length, status);
+    int32_t length = micros.modInner->apply(string, start, end, status);
     if (micros.padding.isValid()) {
         length += micros.padding
-                .padAndApply(*micros.modMiddle, *micros.modOuter, string, 0, length, status);
+                .padAndApply(*micros.modMiddle, *micros.modOuter, string, start, length + end, status);
     } else {
-        length += micros.modMiddle->apply(string, 0, length, status);
-        length += micros.modOuter->apply(string, 0, length, status);
+        length += micros.modMiddle->apply(string, start, length + end, status);
+        length += micros.modOuter->apply(string, start, length + end, status);
     }
     return length;
 }
 
 int32_t NumberFormatterImpl::writeNumber(const MicroProps& micros, DecimalQuantity& quantity,
-                                         NumberStringBuilder& string, UErrorCode& status) {
+                                         NumberStringBuilder& string, int32_t index,
+                                         UErrorCode& status) {
     int32_t length = 0;
     if (quantity.isInfinite()) {
         length += string.insert(
-                length,
+                length + index,
                 micros.symbols->getSymbol(DecimalFormatSymbols::ENumberFormatSymbol::kInfinitySymbol),
                 UNUM_INTEGER_FIELD,
                 status);
 
     } else if (quantity.isNaN()) {
         length += string.insert(
-                length,
+                length + index,
                 micros.symbols->getSymbol(DecimalFormatSymbols::ENumberFormatSymbol::kNaNSymbol),
                 UNUM_INTEGER_FIELD,
                 status);
 
     } else {
         // Add the integer digits
-        length += writeIntegerDigits(micros, quantity, string, status);
+        length += writeIntegerDigits(micros, quantity, string, length + index, status);
 
         // Add the decimal point
         if (quantity.getLowerDisplayMagnitude() < 0 || micros.decimal == UNUM_DECIMAL_SEPARATOR_ALWAYS) {
             length += string.insert(
-                    length,
+                    length + index,
                     micros.useCurrency ? micros.symbols->getSymbol(
                             DecimalFormatSymbols::ENumberFormatSymbol::kMonetarySeparatorSymbol) : micros
                             .symbols
@@ -458,21 +479,22 @@ int32_t NumberFormatterImpl::writeNumber(const MicroProps& micros, DecimalQuanti
         }
 
         // Add the fraction digits
-        length += writeFractionDigits(micros, quantity, string, status);
+        length += writeFractionDigits(micros, quantity, string, length + index, status);
     }
 
     return length;
 }
 
 int32_t NumberFormatterImpl::writeIntegerDigits(const MicroProps& micros, DecimalQuantity& quantity,
-                                                NumberStringBuilder& string, UErrorCode& status) {
+                                                NumberStringBuilder& string, int32_t index,
+                                                UErrorCode& status) {
     int length = 0;
     int integerCount = quantity.getUpperDisplayMagnitude() + 1;
     for (int i = 0; i < integerCount; i++) {
         // Add grouping separator
         if (micros.grouping.groupAtPosition(i, quantity)) {
             length += string.insert(
-                    0,
+                    index,
                     micros.useCurrency ? micros.symbols->getSymbol(
                             DecimalFormatSymbols::ENumberFormatSymbol::kMonetaryGroupingSeparatorSymbol)
                                        : micros.symbols->getSymbol(
@@ -484,20 +506,21 @@ int32_t NumberFormatterImpl::writeIntegerDigits(const MicroProps& micros, Decima
         // Get and append the next digit value
         int8_t nextDigit = quantity.getDigit(i);
         length += utils::insertDigitFromSymbols(
-                string, 0, nextDigit, *micros.symbols, UNUM_INTEGER_FIELD, status);
+                string, index, nextDigit, *micros.symbols, UNUM_INTEGER_FIELD, status);
     }
     return length;
 }
 
 int32_t NumberFormatterImpl::writeFractionDigits(const MicroProps& micros, DecimalQuantity& quantity,
-                                                 NumberStringBuilder& string, UErrorCode& status) {
+                                                 NumberStringBuilder& string, int32_t index,
+                                                 UErrorCode& status) {
     int length = 0;
     int fractionCount = -quantity.getLowerDisplayMagnitude();
     for (int i = 0; i < fractionCount; i++) {
         // Get and append the next digit value
         int8_t nextDigit = quantity.getDigit(-i - 1);
         length += utils::insertDigitFromSymbols(
-                string, string.length(), nextDigit, *micros.symbols, UNUM_FRACTION_FIELD, status);
+                string, length + index, nextDigit, *micros.symbols, UNUM_FRACTION_FIELD, status);
     }
     return length;
 }
index 744fecec13f984ce1ab80ff71a8c016d32131197..2fcc58d34ffda63484456f06ee5d59aa76331a9b 100644 (file)
@@ -35,8 +35,8 @@ class NumberFormatterImpl : public UMemory {
      * Builds and evaluates an "unsafe" MicroPropsGenerator, which is cheaper but can be used only once.
      */
     static void
-    applyStatic(const MacroProps &macros, DecimalQuantity &inValue, NumberStringBuilder &outString,
-                UErrorCode &status);
+    formatStatic(const MacroProps &macros, DecimalQuantity &inValue, NumberStringBuilder &outString,
+                 UErrorCode &status);
 
     /**
      * Prints only the prefix and suffix; used for DecimalFormat getters.
@@ -51,7 +51,12 @@ class NumberFormatterImpl : public UMemory {
     /**
      * Evaluates the "safe" MicroPropsGenerator created by "fromMacros".
      */
-    void apply(DecimalQuantity& inValue, NumberStringBuilder& outString, UErrorCode& status) const;
+    void format(DecimalQuantity& inValue, NumberStringBuilder& outString, UErrorCode& status) const;
+
+    /**
+     * Like format(), but saves the result into an output MicroProps without additional processing.
+     */
+    void preProcess(DecimalQuantity& inValue, MicroProps& microsOut, UErrorCode& status) const;
 
     /**
      * Like getPrefixSuffixStatic() but uses the safe compiled object.
@@ -59,6 +64,19 @@ class NumberFormatterImpl : public UMemory {
     int32_t getPrefixSuffix(int8_t signum, StandardPlural::Form plural, NumberStringBuilder& outString,
                             UErrorCode& status) const;
 
+    /**
+     * Synthesizes the output string from a MicroProps and DecimalQuantity.
+     * This method formats only the main number, not affixes.
+     */
+    static int32_t formatNumber(const MicroProps& micros, DecimalQuantity& quantity,
+                                NumberStringBuilder& string, int32_t index, UErrorCode& status);
+
+    /**
+     * Adds the affixes.  Intended to be called immediately after formatNumber.
+     */
+    static int32_t writeAffixes(const MicroProps& micros, NumberStringBuilder& string, int32_t start,
+                                int32_t end, UErrorCode& status);
+
   private:
     // Head of the MicroPropsGenerator linked list:
     const MicroPropsGenerator *fMicroPropsGenerator = nullptr;
@@ -85,7 +103,7 @@ class NumberFormatterImpl : public UMemory {
 
     NumberFormatterImpl(const MacroProps &macros, bool safe, UErrorCode &status);
 
-    void applyUnsafe(DecimalQuantity &inValue, NumberStringBuilder &outString, UErrorCode &status);
+    MicroProps& preProcessUnsafe(DecimalQuantity &inValue, UErrorCode &status);
 
     int32_t getPrefixSuffixUnsafe(int8_t signum, StandardPlural::Form plural,
                                   NumberStringBuilder& outString, UErrorCode& status);
@@ -113,31 +131,17 @@ class NumberFormatterImpl : public UMemory {
     const MicroPropsGenerator *
     macrosToMicroGenerator(const MacroProps &macros, bool safe, UErrorCode &status);
 
-    /**
-     * Synthesizes the output string from a MicroProps and DecimalQuantity.
-     *
-     * @param micros
-     *            The MicroProps after the quantity has been consumed. Will not be mutated.
-     * @param quantity
-     *            The DecimalQuantity to be rendered. May be mutated.
-     * @param string
-     *            The output string. Will be mutated.
-     */
-    static int32_t
-    microsToString(const MicroProps &micros, DecimalQuantity &quantity, NumberStringBuilder &string,
-                   UErrorCode &status);
-
     static int32_t
     writeNumber(const MicroProps &micros, DecimalQuantity &quantity, NumberStringBuilder &string,
-                UErrorCode &status);
+                int32_t index, UErrorCode &status);
 
     static int32_t
     writeIntegerDigits(const MicroProps &micros, DecimalQuantity &quantity, NumberStringBuilder &string,
-                       UErrorCode &status);
+                       int32_t index, UErrorCode &status);
 
     static int32_t
     writeFractionDigits(const MicroProps &micros, DecimalQuantity &quantity, NumberStringBuilder &string,
-                        UErrorCode &status);
+                        int32_t index, UErrorCode &status);
 };
 
 }  // namespace impl