Jungshik Shin | b318966 | 2017-11-07 11:18:34 -0800 | [diff] [blame] | 1 | // © 2017 and later: Unicode, Inc. and others. |
| 2 | // License & terms of use: http://www.unicode.org/copyright.html |
| 3 | |
| 4 | #include "unicode/utypes.h" |
| 5 | |
Jungshik Shin | a9a2bd3 | 2018-07-07 03:36:01 -0700 | [diff] [blame] | 6 | #if !UCONFIG_NO_FORMATTING |
Jungshik Shin | b318966 | 2017-11-07 11:18:34 -0800 | [diff] [blame] | 7 | |
| 8 | #include "cstring.h" |
| 9 | #include "unicode/ures.h" |
| 10 | #include "uresimp.h" |
| 11 | #include "charstr.h" |
| 12 | #include "number_formatimpl.h" |
| 13 | #include "unicode/numfmt.h" |
| 14 | #include "number_patternstring.h" |
| 15 | #include "number_utils.h" |
| 16 | #include "unicode/numberformatter.h" |
| 17 | #include "unicode/dcfmtsym.h" |
| 18 | #include "number_scientific.h" |
| 19 | #include "number_compact.h" |
Jungshik Shin | f61e46d | 2018-05-04 13:00:45 -0700 | [diff] [blame] | 20 | #include "uresimp.h" |
| 21 | #include "ureslocs.h" |
Jungshik Shin | b318966 | 2017-11-07 11:18:34 -0800 | [diff] [blame] | 22 | |
| 23 | using namespace icu; |
| 24 | using namespace icu::number; |
| 25 | using namespace icu::number::impl; |
| 26 | |
Jungshik Shin | a9a2bd3 | 2018-07-07 03:36:01 -0700 | [diff] [blame] | 27 | |
Jungshik Shin | 42d5027 | 2018-10-24 01:22:09 -0700 | [diff] [blame] | 28 | NumberFormatterImpl::NumberFormatterImpl(const MacroProps& macros, UErrorCode& status) |
| 29 | : NumberFormatterImpl(macros, true, status) { |
Jungshik Shin | b318966 | 2017-11-07 11:18:34 -0800 | [diff] [blame] | 30 | } |
| 31 | |
Frank Tang | f90543d | 2020-10-30 19:02:04 -0700 | [diff] [blame] | 32 | int32_t NumberFormatterImpl::formatStatic(const MacroProps ¯os, UFormattedNumberData *results, |
| 33 | UErrorCode &status) { |
| 34 | DecimalQuantity &inValue = results->quantity; |
| 35 | FormattedStringBuilder &outString = results->getStringRef(); |
Jungshik Shin | b318966 | 2017-11-07 11:18:34 -0800 | [diff] [blame] | 36 | NumberFormatterImpl impl(macros, false, status); |
Jungshik Shin | 42d5027 | 2018-10-24 01:22:09 -0700 | [diff] [blame] | 37 | MicroProps& micros = impl.preProcessUnsafe(inValue, status); |
| 38 | if (U_FAILURE(status)) { return 0; } |
| 39 | int32_t length = writeNumber(micros, inValue, outString, 0, status); |
| 40 | length += writeAffixes(micros, outString, 0, length, status); |
Frank Tang | f90543d | 2020-10-30 19:02:04 -0700 | [diff] [blame] | 41 | results->outputUnit = std::move(micros.outputUnit); |
Frank Tang | 7e7574b | 2021-04-13 21:19:13 -0700 | [diff] [blame] | 42 | results->gender = micros.gender; |
Jungshik Shin | 42d5027 | 2018-10-24 01:22:09 -0700 | [diff] [blame] | 43 | return length; |
Jungshik Shin | b318966 | 2017-11-07 11:18:34 -0800 | [diff] [blame] | 44 | } |
| 45 | |
Frank Tang | b869661 | 2019-10-25 14:58:21 -0700 | [diff] [blame] | 46 | int32_t NumberFormatterImpl::getPrefixSuffixStatic(const MacroProps& macros, Signum signum, |
Jungshik Shin | a9a2bd3 | 2018-07-07 03:36:01 -0700 | [diff] [blame] | 47 | StandardPlural::Form plural, |
Frank Tang | b869661 | 2019-10-25 14:58:21 -0700 | [diff] [blame] | 48 | FormattedStringBuilder& outString, UErrorCode& status) { |
Jungshik Shin | a9a2bd3 | 2018-07-07 03:36:01 -0700 | [diff] [blame] | 49 | NumberFormatterImpl impl(macros, false, status); |
| 50 | return impl.getPrefixSuffixUnsafe(signum, plural, outString, status); |
| 51 | } |
| 52 | |
Jungshik Shin | b318966 | 2017-11-07 11:18:34 -0800 | [diff] [blame] | 53 | // NOTE: C++ SPECIFIC DIFFERENCE FROM JAVA: |
| 54 | // The "safe" apply method uses a new MicroProps. In the MicroPropsGenerator, fMicros is copied into the new instance. |
| 55 | // The "unsafe" method simply re-uses fMicros, eliminating the extra copy operation. |
| 56 | // See MicroProps::processQuantity() for details. |
| 57 | |
Frank Tang | f90543d | 2020-10-30 19:02:04 -0700 | [diff] [blame] | 58 | int32_t NumberFormatterImpl::format(UFormattedNumberData *results, UErrorCode &status) const { |
| 59 | DecimalQuantity &inValue = results->quantity; |
| 60 | FormattedStringBuilder &outString = results->getStringRef(); |
Jungshik Shin | b318966 | 2017-11-07 11:18:34 -0800 | [diff] [blame] | 61 | MicroProps micros; |
Jungshik Shin | 42d5027 | 2018-10-24 01:22:09 -0700 | [diff] [blame] | 62 | preProcess(inValue, micros, status); |
| 63 | if (U_FAILURE(status)) { return 0; } |
| 64 | int32_t length = writeNumber(micros, inValue, outString, 0, status); |
| 65 | length += writeAffixes(micros, outString, 0, length, status); |
Frank Tang | f90543d | 2020-10-30 19:02:04 -0700 | [diff] [blame] | 66 | results->outputUnit = std::move(micros.outputUnit); |
Frank Tang | 7e7574b | 2021-04-13 21:19:13 -0700 | [diff] [blame] | 67 | results->gender = micros.gender; |
Jungshik Shin | 42d5027 | 2018-10-24 01:22:09 -0700 | [diff] [blame] | 68 | return length; |
Jungshik Shin | b318966 | 2017-11-07 11:18:34 -0800 | [diff] [blame] | 69 | } |
| 70 | |
Jungshik Shin | 42d5027 | 2018-10-24 01:22:09 -0700 | [diff] [blame] | 71 | void NumberFormatterImpl::preProcess(DecimalQuantity& inValue, MicroProps& microsOut, |
| 72 | UErrorCode& status) const { |
Jungshik Shin | b318966 | 2017-11-07 11:18:34 -0800 | [diff] [blame] | 73 | if (U_FAILURE(status)) { return; } |
Jungshik Shin | 42d5027 | 2018-10-24 01:22:09 -0700 | [diff] [blame] | 74 | if (fMicroPropsGenerator == nullptr) { |
| 75 | status = U_INTERNAL_PROGRAM_ERROR; |
| 76 | return; |
| 77 | } |
| 78 | fMicroPropsGenerator->processQuantity(inValue, microsOut, status); |
Jungshik Shin | 42d5027 | 2018-10-24 01:22:09 -0700 | [diff] [blame] | 79 | microsOut.integerWidth.apply(inValue, status); |
| 80 | } |
| 81 | |
| 82 | MicroProps& NumberFormatterImpl::preProcessUnsafe(DecimalQuantity& inValue, UErrorCode& status) { |
| 83 | if (U_FAILURE(status)) { |
| 84 | return fMicros; // must always return a value |
| 85 | } |
| 86 | if (fMicroPropsGenerator == nullptr) { |
| 87 | status = U_INTERNAL_PROGRAM_ERROR; |
| 88 | return fMicros; // must always return a value |
| 89 | } |
Jungshik Shin | b318966 | 2017-11-07 11:18:34 -0800 | [diff] [blame] | 90 | fMicroPropsGenerator->processQuantity(inValue, fMicros, status); |
Jungshik Shin | 42d5027 | 2018-10-24 01:22:09 -0700 | [diff] [blame] | 91 | fMicros.integerWidth.apply(inValue, status); |
| 92 | return fMicros; |
Jungshik Shin | b318966 | 2017-11-07 11:18:34 -0800 | [diff] [blame] | 93 | } |
| 94 | |
Frank Tang | b869661 | 2019-10-25 14:58:21 -0700 | [diff] [blame] | 95 | int32_t NumberFormatterImpl::getPrefixSuffix(Signum signum, StandardPlural::Form plural, |
| 96 | FormattedStringBuilder& outString, UErrorCode& status) const { |
Jungshik Shin | a9a2bd3 | 2018-07-07 03:36:01 -0700 | [diff] [blame] | 97 | if (U_FAILURE(status)) { return 0; } |
| 98 | // #13453: DecimalFormat wants the affixes from the pattern only (modMiddle, aka pattern modifier). |
| 99 | // Safe path: use fImmutablePatternModifier. |
| 100 | const Modifier* modifier = fImmutablePatternModifier->getModifier(signum, plural); |
| 101 | modifier->apply(outString, 0, 0, status); |
| 102 | if (U_FAILURE(status)) { return 0; } |
Jungshik Shin | 42d5027 | 2018-10-24 01:22:09 -0700 | [diff] [blame] | 103 | return modifier->getPrefixLength(); |
Jungshik Shin | a9a2bd3 | 2018-07-07 03:36:01 -0700 | [diff] [blame] | 104 | } |
| 105 | |
Frank Tang | b869661 | 2019-10-25 14:58:21 -0700 | [diff] [blame] | 106 | int32_t NumberFormatterImpl::getPrefixSuffixUnsafe(Signum signum, StandardPlural::Form plural, |
| 107 | FormattedStringBuilder& outString, UErrorCode& status) { |
Jungshik Shin | a9a2bd3 | 2018-07-07 03:36:01 -0700 | [diff] [blame] | 108 | if (U_FAILURE(status)) { return 0; } |
| 109 | // #13453: DecimalFormat wants the affixes from the pattern only (modMiddle, aka pattern modifier). |
| 110 | // Unsafe path: use fPatternModifier. |
| 111 | fPatternModifier->setNumberProperties(signum, plural); |
| 112 | fPatternModifier->apply(outString, 0, 0, status); |
| 113 | if (U_FAILURE(status)) { return 0; } |
Jungshik Shin | 42d5027 | 2018-10-24 01:22:09 -0700 | [diff] [blame] | 114 | return fPatternModifier->getPrefixLength(); |
Jungshik Shin | a9a2bd3 | 2018-07-07 03:36:01 -0700 | [diff] [blame] | 115 | } |
| 116 | |
| 117 | NumberFormatterImpl::NumberFormatterImpl(const MacroProps& macros, bool safe, UErrorCode& status) { |
Jungshik Shin | b318966 | 2017-11-07 11:18:34 -0800 | [diff] [blame] | 118 | fMicroPropsGenerator = macrosToMicroGenerator(macros, safe, status); |
| 119 | } |
| 120 | |
| 121 | ////////// |
| 122 | |
Jungshik Shin | a9a2bd3 | 2018-07-07 03:36:01 -0700 | [diff] [blame] | 123 | const MicroPropsGenerator* |
| 124 | NumberFormatterImpl::macrosToMicroGenerator(const MacroProps& macros, bool safe, UErrorCode& status) { |
| 125 | if (U_FAILURE(status)) { return nullptr; } |
| 126 | const MicroPropsGenerator* chain = &fMicros; |
Jungshik Shin | b318966 | 2017-11-07 11:18:34 -0800 | [diff] [blame] | 127 | |
| 128 | // Check that macros is error-free before continuing. |
| 129 | if (macros.copyErrorTo(status)) { |
| 130 | return nullptr; |
| 131 | } |
| 132 | |
| 133 | // TODO: Accept currency symbols from DecimalFormatSymbols? |
| 134 | |
| 135 | // Pre-compute a few values for efficiency. |
Jungshik Shin | a9a2bd3 | 2018-07-07 03:36:01 -0700 | [diff] [blame] | 136 | bool isCurrency = utils::unitIsCurrency(macros.unit); |
Frank Tang | f90543d | 2020-10-30 19:02:04 -0700 | [diff] [blame] | 137 | bool isBaseUnit = utils::unitIsBaseUnit(macros.unit); |
Frank Tang | 69c72a6 | 2019-04-03 21:41:21 -0700 | [diff] [blame] | 138 | bool isPercent = utils::unitIsPercent(macros.unit); |
| 139 | bool isPermille = utils::unitIsPermille(macros.unit); |
Frank Tang | f90543d | 2020-10-30 19:02:04 -0700 | [diff] [blame] | 140 | bool isCompactNotation = macros.notation.fType == Notation::NTN_COMPACT; |
Jungshik Shin | a9a2bd3 | 2018-07-07 03:36:01 -0700 | [diff] [blame] | 141 | bool isAccounting = |
Frank Tang | 7e7574b | 2021-04-13 21:19:13 -0700 | [diff] [blame] | 142 | macros.sign == UNUM_SIGN_ACCOUNTING || |
| 143 | macros.sign == UNUM_SIGN_ACCOUNTING_ALWAYS || |
| 144 | macros.sign == UNUM_SIGN_ACCOUNTING_EXCEPT_ZERO || |
| 145 | macros.sign == UNUM_SIGN_ACCOUNTING_NEGATIVE; |
Frank Tang | 69c72a6 | 2019-04-03 21:41:21 -0700 | [diff] [blame] | 146 | CurrencyUnit currency(u"", status); |
Jungshik Shin | b318966 | 2017-11-07 11:18:34 -0800 | [diff] [blame] | 147 | if (isCurrency) { |
| 148 | currency = CurrencyUnit(macros.unit, status); // Restore CurrencyUnit from MeasureUnit |
| 149 | } |
| 150 | UNumberUnitWidth unitWidth = UNUM_UNIT_WIDTH_SHORT; |
| 151 | if (macros.unitWidth != UNUM_UNIT_WIDTH_COUNT) { |
| 152 | unitWidth = macros.unitWidth; |
| 153 | } |
Frank Tang | f90543d | 2020-10-30 19:02:04 -0700 | [diff] [blame] | 154 | // Use CLDR unit data for all MeasureUnits (not currency and not |
| 155 | // no-unit), except use the dedicated percent pattern for percent and |
| 156 | // permille. However, use the CLDR unit data for percent/permille if a |
| 157 | // long name was requested OR if compact notation is being used, since |
| 158 | // compact notation overrides the middle modifier (micros.modMiddle) |
| 159 | // normally used for the percent pattern. |
| 160 | bool isCldrUnit = !isCurrency |
| 161 | && !isBaseUnit |
| 162 | && (unitWidth == UNUM_UNIT_WIDTH_FULL_NAME |
| 163 | || !(isPercent || isPermille) |
| 164 | || isCompactNotation |
| 165 | ); |
| 166 | bool isMixedUnit = isCldrUnit && (uprv_strcmp(macros.unit.getType(), "") == 0) && |
| 167 | macros.unit.getComplexity(status) == UMEASURE_UNIT_MIXED; |
Jungshik Shin | b318966 | 2017-11-07 11:18:34 -0800 | [diff] [blame] | 168 | |
| 169 | // Select the numbering system. |
| 170 | LocalPointer<const NumberingSystem> nsLocal; |
Jungshik Shin | a9a2bd3 | 2018-07-07 03:36:01 -0700 | [diff] [blame] | 171 | const NumberingSystem* ns; |
Jungshik Shin | b318966 | 2017-11-07 11:18:34 -0800 | [diff] [blame] | 172 | if (macros.symbols.isNumberingSystem()) { |
| 173 | ns = macros.symbols.getNumberingSystem(); |
| 174 | } else { |
| 175 | // TODO: Is there a way to avoid creating the NumberingSystem object? |
| 176 | ns = NumberingSystem::createInstance(macros.locale, status); |
| 177 | // Give ownership to the function scope. |
| 178 | nsLocal.adoptInstead(ns); |
| 179 | } |
Jungshik Shin | a9a2bd3 | 2018-07-07 03:36:01 -0700 | [diff] [blame] | 180 | const char* nsName = U_SUCCESS(status) ? ns->getName() : "latn"; |
Frank Tang | 69c72a6 | 2019-04-03 21:41:21 -0700 | [diff] [blame] | 181 | uprv_strncpy(fMicros.nsName, nsName, 8); |
| 182 | fMicros.nsName[8] = 0; // guarantee NUL-terminated |
Jungshik Shin | b318966 | 2017-11-07 11:18:34 -0800 | [diff] [blame] | 183 | |
Frank Tang | 7e7574b | 2021-04-13 21:19:13 -0700 | [diff] [blame] | 184 | // Default gender: none. |
| 185 | fMicros.gender = ""; |
| 186 | |
Jungshik Shin | f61e46d | 2018-05-04 13:00:45 -0700 | [diff] [blame] | 187 | // Resolve the symbols. Do this here because currency may need to customize them. |
Jungshik Shin | b318966 | 2017-11-07 11:18:34 -0800 | [diff] [blame] | 188 | if (macros.symbols.isDecimalFormatSymbols()) { |
| 189 | fMicros.symbols = macros.symbols.getDecimalFormatSymbols(); |
| 190 | } else { |
Frank Tang | f222396 | 2020-04-27 18:25:29 -0700 | [diff] [blame] | 191 | LocalPointer<DecimalFormatSymbols> newSymbols( |
| 192 | new DecimalFormatSymbols(macros.locale, *ns, status), status); |
| 193 | if (U_FAILURE(status)) { |
Frank Tang | b869661 | 2019-10-25 14:58:21 -0700 | [diff] [blame] | 194 | return nullptr; |
| 195 | } |
Frank Tang | f222396 | 2020-04-27 18:25:29 -0700 | [diff] [blame] | 196 | if (isCurrency) { |
| 197 | newSymbols->setCurrency(currency.getISOCurrency(), status); |
| 198 | if (U_FAILURE(status)) { |
| 199 | return nullptr; |
| 200 | } |
| 201 | } |
| 202 | fMicros.symbols = newSymbols.getAlias(); |
| 203 | fSymbols.adoptInstead(newSymbols.orphan()); |
Jungshik Shin | b318966 | 2017-11-07 11:18:34 -0800 | [diff] [blame] | 204 | } |
| 205 | |
Jungshik Shin | f61e46d | 2018-05-04 13:00:45 -0700 | [diff] [blame] | 206 | // Load and parse the pattern string. It is used for grouping sizes and affixes only. |
| 207 | // If we are formatting currency, check for a currency-specific pattern. |
| 208 | const char16_t* pattern = nullptr; |
Frank Tang | f222396 | 2020-04-27 18:25:29 -0700 | [diff] [blame] | 209 | if (isCurrency && fMicros.symbols->getCurrencyPattern() != nullptr) { |
| 210 | pattern = fMicros.symbols->getCurrencyPattern(); |
Jungshik Shin | f61e46d | 2018-05-04 13:00:45 -0700 | [diff] [blame] | 211 | } |
| 212 | if (pattern == nullptr) { |
| 213 | CldrPatternStyle patternStyle; |
Frank Tang | 69c72a6 | 2019-04-03 21:41:21 -0700 | [diff] [blame] | 214 | if (isCldrUnit) { |
| 215 | patternStyle = CLDR_PATTERN_STYLE_DECIMAL; |
| 216 | } else if (isPercent || isPermille) { |
Jungshik Shin | f61e46d | 2018-05-04 13:00:45 -0700 | [diff] [blame] | 217 | patternStyle = CLDR_PATTERN_STYLE_PERCENT; |
| 218 | } else if (!isCurrency || unitWidth == UNUM_UNIT_WIDTH_FULL_NAME) { |
| 219 | patternStyle = CLDR_PATTERN_STYLE_DECIMAL; |
| 220 | } else if (isAccounting) { |
| 221 | // NOTE: Although ACCOUNTING and ACCOUNTING_ALWAYS are only supported in currencies right now, |
| 222 | // the API contract allows us to add support to other units in the future. |
| 223 | patternStyle = CLDR_PATTERN_STYLE_ACCOUNTING; |
| 224 | } else { |
| 225 | patternStyle = CLDR_PATTERN_STYLE_CURRENCY; |
| 226 | } |
Jungshik Shin | a9a2bd3 | 2018-07-07 03:36:01 -0700 | [diff] [blame] | 227 | pattern = utils::getPatternForStyle(macros.locale, nsName, patternStyle, status); |
Frank Tang | f222396 | 2020-04-27 18:25:29 -0700 | [diff] [blame] | 228 | if (U_FAILURE(status)) { |
| 229 | return nullptr; |
| 230 | } |
Jungshik Shin | f61e46d | 2018-05-04 13:00:45 -0700 | [diff] [blame] | 231 | } |
| 232 | auto patternInfo = new ParsedPatternInfo(); |
Frank Tang | b869661 | 2019-10-25 14:58:21 -0700 | [diff] [blame] | 233 | if (patternInfo == nullptr) { |
| 234 | status = U_MEMORY_ALLOCATION_ERROR; |
| 235 | return nullptr; |
| 236 | } |
Jungshik Shin | f61e46d | 2018-05-04 13:00:45 -0700 | [diff] [blame] | 237 | fPatternInfo.adoptInstead(patternInfo); |
| 238 | PatternParser::parseToPatternInfo(UnicodeString(pattern), *patternInfo, status); |
Frank Tang | f222396 | 2020-04-27 18:25:29 -0700 | [diff] [blame] | 239 | if (U_FAILURE(status)) { |
| 240 | return nullptr; |
| 241 | } |
Jungshik Shin | f61e46d | 2018-05-04 13:00:45 -0700 | [diff] [blame] | 242 | |
| 243 | ///////////////////////////////////////////////////////////////////////////////////// |
| 244 | /// START POPULATING THE DEFAULT MICROPROPS AND BUILDING THE MICROPROPS GENERATOR /// |
| 245 | ///////////////////////////////////////////////////////////////////////////////////// |
| 246 | |
Frank Tang | f90543d | 2020-10-30 19:02:04 -0700 | [diff] [blame] | 247 | // Unit Preferences and Conversions as our first step |
| 248 | if (macros.usage.isSet()) { |
| 249 | if (!isCldrUnit) { |
| 250 | // We only support "usage" when the input unit is specified, and is |
| 251 | // a CLDR Unit. |
| 252 | status = U_ILLEGAL_ARGUMENT_ERROR; |
| 253 | return nullptr; |
| 254 | } |
| 255 | auto usagePrefsHandler = |
Frank Tang | 7e7574b | 2021-04-13 21:19:13 -0700 | [diff] [blame] | 256 | new UsagePrefsHandler(macros.locale, macros.unit, macros.usage.fValue, chain, status); |
Frank Tang | f90543d | 2020-10-30 19:02:04 -0700 | [diff] [blame] | 257 | fUsagePrefsHandler.adoptInsteadAndCheckErrorCode(usagePrefsHandler, status); |
| 258 | chain = fUsagePrefsHandler.getAlias(); |
| 259 | } else if (isMixedUnit) { |
Frank Tang | 7e7574b | 2021-04-13 21:19:13 -0700 | [diff] [blame] | 260 | auto unitConversionHandler = new UnitConversionHandler(macros.unit, chain, status); |
Frank Tang | f90543d | 2020-10-30 19:02:04 -0700 | [diff] [blame] | 261 | fUnitConversionHandler.adoptInsteadAndCheckErrorCode(unitConversionHandler, status); |
| 262 | chain = fUnitConversionHandler.getAlias(); |
| 263 | } |
| 264 | |
Jungshik Shin | a9a2bd3 | 2018-07-07 03:36:01 -0700 | [diff] [blame] | 265 | // Multiplier |
| 266 | if (macros.scale.isValid()) { |
| 267 | fMicros.helpers.multiplier.setAndChain(macros.scale, chain); |
| 268 | chain = &fMicros.helpers.multiplier; |
Jungshik Shin | b318966 | 2017-11-07 11:18:34 -0800 | [diff] [blame] | 269 | } |
Jungshik Shin | a9a2bd3 | 2018-07-07 03:36:01 -0700 | [diff] [blame] | 270 | |
| 271 | // Rounding strategy |
| 272 | Precision precision; |
| 273 | if (!macros.precision.isBogus()) { |
| 274 | precision = macros.precision; |
Frank Tang | f90543d | 2020-10-30 19:02:04 -0700 | [diff] [blame] | 275 | } else if (isCompactNotation) { |
Jungshik Shin | a9a2bd3 | 2018-07-07 03:36:01 -0700 | [diff] [blame] | 276 | precision = Precision::integer().withMinDigits(2); |
| 277 | } else if (isCurrency) { |
| 278 | precision = Precision::currency(UCURR_USAGE_STANDARD); |
Frank Tang | f90543d | 2020-10-30 19:02:04 -0700 | [diff] [blame] | 279 | } else if (macros.usage.isSet()) { |
| 280 | // Bogus Precision - it will get set in the UsagePrefsHandler instead |
| 281 | precision = Precision(); |
Jungshik Shin | a9a2bd3 | 2018-07-07 03:36:01 -0700 | [diff] [blame] | 282 | } else { |
| 283 | precision = Precision::maxFraction(6); |
| 284 | } |
| 285 | UNumberFormatRoundingMode roundingMode; |
Frank Tang | f90543d | 2020-10-30 19:02:04 -0700 | [diff] [blame] | 286 | roundingMode = macros.roundingMode; |
Jungshik Shin | a9a2bd3 | 2018-07-07 03:36:01 -0700 | [diff] [blame] | 287 | fMicros.rounder = {precision, roundingMode, currency, status}; |
Frank Tang | f222396 | 2020-04-27 18:25:29 -0700 | [diff] [blame] | 288 | if (U_FAILURE(status)) { |
| 289 | return nullptr; |
| 290 | } |
Jungshik Shin | b318966 | 2017-11-07 11:18:34 -0800 | [diff] [blame] | 291 | |
| 292 | // Grouping strategy |
| 293 | if (!macros.grouper.isBogus()) { |
| 294 | fMicros.grouping = macros.grouper; |
Frank Tang | f90543d | 2020-10-30 19:02:04 -0700 | [diff] [blame] | 295 | } else if (isCompactNotation) { |
Jungshik Shin | b318966 | 2017-11-07 11:18:34 -0800 | [diff] [blame] | 296 | // Compact notation uses minGrouping by default since ICU 59 |
Jungshik Shin | f61e46d | 2018-05-04 13:00:45 -0700 | [diff] [blame] | 297 | fMicros.grouping = Grouper::forStrategy(UNUM_GROUPING_MIN2); |
Jungshik Shin | b318966 | 2017-11-07 11:18:34 -0800 | [diff] [blame] | 298 | } else { |
Jungshik Shin | f61e46d | 2018-05-04 13:00:45 -0700 | [diff] [blame] | 299 | fMicros.grouping = Grouper::forStrategy(UNUM_GROUPING_AUTO); |
Jungshik Shin | b318966 | 2017-11-07 11:18:34 -0800 | [diff] [blame] | 300 | } |
Jungshik Shin | f61e46d | 2018-05-04 13:00:45 -0700 | [diff] [blame] | 301 | fMicros.grouping.setLocaleData(*fPatternInfo, macros.locale); |
Jungshik Shin | b318966 | 2017-11-07 11:18:34 -0800 | [diff] [blame] | 302 | |
| 303 | // Padding strategy |
| 304 | if (!macros.padder.isBogus()) { |
| 305 | fMicros.padding = macros.padder; |
| 306 | } else { |
| 307 | fMicros.padding = Padder::none(); |
| 308 | } |
| 309 | |
| 310 | // Integer width |
| 311 | if (!macros.integerWidth.isBogus()) { |
| 312 | fMicros.integerWidth = macros.integerWidth; |
| 313 | } else { |
Jungshik Shin | a9a2bd3 | 2018-07-07 03:36:01 -0700 | [diff] [blame] | 314 | fMicros.integerWidth = IntegerWidth::standard(); |
Jungshik Shin | b318966 | 2017-11-07 11:18:34 -0800 | [diff] [blame] | 315 | } |
| 316 | |
| 317 | // Sign display |
| 318 | if (macros.sign != UNUM_SIGN_COUNT) { |
| 319 | fMicros.sign = macros.sign; |
| 320 | } else { |
| 321 | fMicros.sign = UNUM_SIGN_AUTO; |
| 322 | } |
| 323 | |
| 324 | // Decimal mark display |
| 325 | if (macros.decimal != UNUM_DECIMAL_SEPARATOR_COUNT) { |
| 326 | fMicros.decimal = macros.decimal; |
| 327 | } else { |
| 328 | fMicros.decimal = UNUM_DECIMAL_SEPARATOR_AUTO; |
| 329 | } |
| 330 | |
| 331 | // Use monetary separator symbols |
| 332 | fMicros.useCurrency = isCurrency; |
| 333 | |
| 334 | // Inner modifier (scientific notation) |
| 335 | if (macros.notation.fType == Notation::NTN_SCIENTIFIC) { |
Frank Tang | b869661 | 2019-10-25 14:58:21 -0700 | [diff] [blame] | 336 | auto newScientificHandler = new ScientificHandler(¯os.notation, fMicros.symbols, chain); |
| 337 | if (newScientificHandler == nullptr) { |
| 338 | status = U_MEMORY_ALLOCATION_ERROR; |
| 339 | return nullptr; |
| 340 | } |
| 341 | fScientificHandler.adoptInstead(newScientificHandler); |
Jungshik Shin | b318966 | 2017-11-07 11:18:34 -0800 | [diff] [blame] | 342 | chain = fScientificHandler.getAlias(); |
| 343 | } else { |
| 344 | // No inner modifier required |
| 345 | fMicros.modInner = &fMicros.helpers.emptyStrongModifier; |
| 346 | } |
| 347 | |
| 348 | // Middle modifier (patterns, positive/negative, currency symbols, percent) |
| 349 | auto patternModifier = new MutablePatternModifier(false); |
Frank Tang | b869661 | 2019-10-25 14:58:21 -0700 | [diff] [blame] | 350 | if (patternModifier == nullptr) { |
| 351 | status = U_MEMORY_ALLOCATION_ERROR; |
| 352 | return nullptr; |
| 353 | } |
Jungshik Shin | b318966 | 2017-11-07 11:18:34 -0800 | [diff] [blame] | 354 | fPatternModifier.adoptInstead(patternModifier); |
Frank Tang | 3e05d9d | 2021-11-08 14:04:04 -0800 | [diff] [blame] | 355 | const AffixPatternProvider* affixProvider = |
Frank Tang | 1f164ee | 2022-11-08 12:31:27 -0800 | [diff] [blame^] | 356 | macros.affixProvider != nullptr && ( |
| 357 | // For more information on this condition, see ICU-22073 |
| 358 | !isCompactNotation || isCurrency == macros.affixProvider->hasCurrencySign()) |
Frank Tang | 3e05d9d | 2021-11-08 14:04:04 -0800 | [diff] [blame] | 359 | ? macros.affixProvider |
| 360 | : static_cast<const AffixPatternProvider*>(fPatternInfo.getAlias()); |
| 361 | patternModifier->setPatternInfo(affixProvider, kUndefinedField); |
| 362 | patternModifier->setPatternAttributes(fMicros.sign, isPermille, macros.approximately); |
Jungshik Shin | b318966 | 2017-11-07 11:18:34 -0800 | [diff] [blame] | 363 | if (patternModifier->needsPlurals()) { |
| 364 | patternModifier->setSymbols( |
| 365 | fMicros.symbols, |
Frank Tang | f222396 | 2020-04-27 18:25:29 -0700 | [diff] [blame] | 366 | currency, |
Jungshik Shin | b318966 | 2017-11-07 11:18:34 -0800 | [diff] [blame] | 367 | unitWidth, |
Frank Tang | f222396 | 2020-04-27 18:25:29 -0700 | [diff] [blame] | 368 | resolvePluralRules(macros.rules, macros.locale, status), |
| 369 | status); |
Jungshik Shin | b318966 | 2017-11-07 11:18:34 -0800 | [diff] [blame] | 370 | } else { |
Frank Tang | f222396 | 2020-04-27 18:25:29 -0700 | [diff] [blame] | 371 | patternModifier->setSymbols(fMicros.symbols, currency, unitWidth, nullptr, status); |
Jungshik Shin | b318966 | 2017-11-07 11:18:34 -0800 | [diff] [blame] | 372 | } |
| 373 | if (safe) { |
Frank Tang | f90543d | 2020-10-30 19:02:04 -0700 | [diff] [blame] | 374 | fImmutablePatternModifier.adoptInsteadAndCheckErrorCode(patternModifier->createImmutable(status), |
| 375 | status); |
Frank Tang | f222396 | 2020-04-27 18:25:29 -0700 | [diff] [blame] | 376 | } |
| 377 | if (U_FAILURE(status)) { |
| 378 | return nullptr; |
Jungshik Shin | b318966 | 2017-11-07 11:18:34 -0800 | [diff] [blame] | 379 | } |
| 380 | |
Frank Tang | 3e05d9d | 2021-11-08 14:04:04 -0800 | [diff] [blame] | 381 | // currencyAsDecimal |
| 382 | if (affixProvider->currencyAsDecimal()) { |
| 383 | fMicros.currencyAsDecimal = patternModifier->getCurrencySymbolForUnitWidth(status); |
| 384 | } |
| 385 | |
Jungshik Shin | b318966 | 2017-11-07 11:18:34 -0800 | [diff] [blame] | 386 | // Outer modifier (CLDR units and currency long names) |
| 387 | if (isCldrUnit) { |
Frank Tang | 7e7574b | 2021-04-13 21:19:13 -0700 | [diff] [blame] | 388 | const char *unitDisplayCase = ""; |
| 389 | if (macros.unitDisplayCase.isSet()) { |
| 390 | unitDisplayCase = macros.unitDisplayCase.fValue; |
| 391 | } |
Frank Tang | f90543d | 2020-10-30 19:02:04 -0700 | [diff] [blame] | 392 | if (macros.usage.isSet()) { |
| 393 | fLongNameMultiplexer.adoptInsteadAndCheckErrorCode( |
| 394 | LongNameMultiplexer::forMeasureUnits( |
Frank Tang | 7e7574b | 2021-04-13 21:19:13 -0700 | [diff] [blame] | 395 | macros.locale, *fUsagePrefsHandler->getOutputUnits(), unitWidth, unitDisplayCase, |
Frank Tang | f90543d | 2020-10-30 19:02:04 -0700 | [diff] [blame] | 396 | resolvePluralRules(macros.rules, macros.locale, status), chain, status), |
| 397 | status); |
| 398 | chain = fLongNameMultiplexer.getAlias(); |
| 399 | } else if (isMixedUnit) { |
| 400 | fMixedUnitLongNameHandler.adoptInsteadAndCheckErrorCode(new MixedUnitLongNameHandler(), |
| 401 | status); |
| 402 | MixedUnitLongNameHandler::forMeasureUnit( |
Frank Tang | 7e7574b | 2021-04-13 21:19:13 -0700 | [diff] [blame] | 403 | macros.locale, macros.unit, unitWidth, unitDisplayCase, |
Frank Tang | f90543d | 2020-10-30 19:02:04 -0700 | [diff] [blame] | 404 | resolvePluralRules(macros.rules, macros.locale, status), chain, |
| 405 | fMixedUnitLongNameHandler.getAlias(), status); |
| 406 | chain = fMixedUnitLongNameHandler.getAlias(); |
| 407 | } else { |
Frank Tang | 7e7574b | 2021-04-13 21:19:13 -0700 | [diff] [blame] | 408 | MeasureUnit unit = macros.unit; |
| 409 | if (!utils::unitIsBaseUnit(macros.perUnit)) { |
| 410 | unit = unit.product(macros.perUnit.reciprocal(status), status); |
| 411 | // This isn't strictly necessary, but was what we specced out |
| 412 | // when perUnit became a backward-compatibility thing: |
| 413 | // unit/perUnit use case is only valid if both units are |
| 414 | // built-ins, or the product is a built-in. |
| 415 | if (uprv_strcmp(unit.getType(), "") == 0 && |
| 416 | (uprv_strcmp(macros.unit.getType(), "") == 0 || |
| 417 | uprv_strcmp(macros.perUnit.getType(), "") == 0)) { |
| 418 | status = U_UNSUPPORTED_ERROR; |
| 419 | return nullptr; |
| 420 | } |
| 421 | } |
Frank Tang | f90543d | 2020-10-30 19:02:04 -0700 | [diff] [blame] | 422 | fLongNameHandler.adoptInsteadAndCheckErrorCode(new LongNameHandler(), status); |
Frank Tang | 7e7574b | 2021-04-13 21:19:13 -0700 | [diff] [blame] | 423 | LongNameHandler::forMeasureUnit(macros.locale, unit, unitWidth, unitDisplayCase, |
Frank Tang | f90543d | 2020-10-30 19:02:04 -0700 | [diff] [blame] | 424 | resolvePluralRules(macros.rules, macros.locale, status), |
| 425 | chain, fLongNameHandler.getAlias(), status); |
| 426 | chain = fLongNameHandler.getAlias(); |
| 427 | } |
Jungshik Shin | b318966 | 2017-11-07 11:18:34 -0800 | [diff] [blame] | 428 | } else if (isCurrency && unitWidth == UNUM_UNIT_WIDTH_FULL_NAME) { |
Frank Tang | f90543d | 2020-10-30 19:02:04 -0700 | [diff] [blame] | 429 | fLongNameHandler.adoptInsteadAndCheckErrorCode( |
| 430 | LongNameHandler::forCurrencyLongNames( |
| 431 | macros.locale, currency, resolvePluralRules(macros.rules, macros.locale, status), chain, |
| 432 | status), |
| 433 | status); |
Jungshik Shin | b318966 | 2017-11-07 11:18:34 -0800 | [diff] [blame] | 434 | chain = fLongNameHandler.getAlias(); |
| 435 | } else { |
| 436 | // No outer modifier required |
| 437 | fMicros.modOuter = &fMicros.helpers.emptyWeakModifier; |
| 438 | } |
Frank Tang | f222396 | 2020-04-27 18:25:29 -0700 | [diff] [blame] | 439 | if (U_FAILURE(status)) { |
| 440 | return nullptr; |
| 441 | } |
Jungshik Shin | b318966 | 2017-11-07 11:18:34 -0800 | [diff] [blame] | 442 | |
| 443 | // Compact notation |
Frank Tang | f90543d | 2020-10-30 19:02:04 -0700 | [diff] [blame] | 444 | if (isCompactNotation) { |
Jungshik Shin | b318966 | 2017-11-07 11:18:34 -0800 | [diff] [blame] | 445 | CompactType compactType = (isCurrency && unitWidth != UNUM_UNIT_WIDTH_FULL_NAME) |
| 446 | ? CompactType::TYPE_CURRENCY : CompactType::TYPE_DECIMAL; |
Frank Tang | b869661 | 2019-10-25 14:58:21 -0700 | [diff] [blame] | 447 | auto newCompactHandler = new CompactHandler( |
| 448 | macros.notation.fUnion.compactStyle, |
| 449 | macros.locale, |
| 450 | nsName, |
| 451 | compactType, |
| 452 | resolvePluralRules(macros.rules, macros.locale, status), |
Frank Tang | f222396 | 2020-04-27 18:25:29 -0700 | [diff] [blame] | 453 | patternModifier, |
| 454 | safe, |
Frank Tang | b869661 | 2019-10-25 14:58:21 -0700 | [diff] [blame] | 455 | chain, |
| 456 | status); |
Frank Tang | f90543d | 2020-10-30 19:02:04 -0700 | [diff] [blame] | 457 | if (U_FAILURE(status)) { |
| 458 | return nullptr; |
| 459 | } |
Frank Tang | b869661 | 2019-10-25 14:58:21 -0700 | [diff] [blame] | 460 | if (newCompactHandler == nullptr) { |
| 461 | status = U_MEMORY_ALLOCATION_ERROR; |
| 462 | return nullptr; |
| 463 | } |
| 464 | fCompactHandler.adoptInstead(newCompactHandler); |
Jungshik Shin | b318966 | 2017-11-07 11:18:34 -0800 | [diff] [blame] | 465 | chain = fCompactHandler.getAlias(); |
| 466 | } |
Frank Tang | f222396 | 2020-04-27 18:25:29 -0700 | [diff] [blame] | 467 | if (U_FAILURE(status)) { |
| 468 | return nullptr; |
| 469 | } |
| 470 | |
| 471 | // Always add the pattern modifier as the last element of the chain. |
| 472 | if (safe) { |
| 473 | fImmutablePatternModifier->addToChain(chain); |
| 474 | chain = fImmutablePatternModifier.getAlias(); |
| 475 | } else { |
| 476 | patternModifier->addToChain(chain); |
| 477 | chain = patternModifier; |
| 478 | } |
Jungshik Shin | b318966 | 2017-11-07 11:18:34 -0800 | [diff] [blame] | 479 | |
| 480 | return chain; |
| 481 | } |
| 482 | |
Jungshik Shin | a9a2bd3 | 2018-07-07 03:36:01 -0700 | [diff] [blame] | 483 | const PluralRules* |
| 484 | NumberFormatterImpl::resolvePluralRules(const PluralRules* rulesPtr, const Locale& locale, |
| 485 | UErrorCode& status) { |
Jungshik Shin | b318966 | 2017-11-07 11:18:34 -0800 | [diff] [blame] | 486 | if (rulesPtr != nullptr) { |
| 487 | return rulesPtr; |
| 488 | } |
| 489 | // Lazily create PluralRules |
| 490 | if (fRules.isNull()) { |
| 491 | fRules.adoptInstead(PluralRules::forLocale(locale, status)); |
| 492 | } |
| 493 | return fRules.getAlias(); |
| 494 | } |
| 495 | |
Frank Tang | b869661 | 2019-10-25 14:58:21 -0700 | [diff] [blame] | 496 | int32_t NumberFormatterImpl::writeAffixes(const MicroProps& micros, FormattedStringBuilder& string, |
Jungshik Shin | 42d5027 | 2018-10-24 01:22:09 -0700 | [diff] [blame] | 497 | int32_t start, int32_t end, UErrorCode& status) { |
Frank Tang | f90543d | 2020-10-30 19:02:04 -0700 | [diff] [blame] | 498 | U_ASSERT(micros.modOuter != nullptr); |
Jungshik Shin | b318966 | 2017-11-07 11:18:34 -0800 | [diff] [blame] | 499 | // Always apply the inner modifier (which is "strong"). |
Jungshik Shin | 42d5027 | 2018-10-24 01:22:09 -0700 | [diff] [blame] | 500 | int32_t length = micros.modInner->apply(string, start, end, status); |
Jungshik Shin | b318966 | 2017-11-07 11:18:34 -0800 | [diff] [blame] | 501 | if (micros.padding.isValid()) { |
| 502 | length += micros.padding |
Jungshik Shin | 42d5027 | 2018-10-24 01:22:09 -0700 | [diff] [blame] | 503 | .padAndApply(*micros.modMiddle, *micros.modOuter, string, start, length + end, status); |
Jungshik Shin | b318966 | 2017-11-07 11:18:34 -0800 | [diff] [blame] | 504 | } else { |
Jungshik Shin | 42d5027 | 2018-10-24 01:22:09 -0700 | [diff] [blame] | 505 | length += micros.modMiddle->apply(string, start, length + end, status); |
| 506 | length += micros.modOuter->apply(string, start, length + end, status); |
Jungshik Shin | b318966 | 2017-11-07 11:18:34 -0800 | [diff] [blame] | 507 | } |
| 508 | return length; |
| 509 | } |
| 510 | |
Jungshik Shin | a9a2bd3 | 2018-07-07 03:36:01 -0700 | [diff] [blame] | 511 | int32_t NumberFormatterImpl::writeNumber(const MicroProps& micros, DecimalQuantity& quantity, |
Frank Tang | b869661 | 2019-10-25 14:58:21 -0700 | [diff] [blame] | 512 | FormattedStringBuilder& string, int32_t index, |
Jungshik Shin | 42d5027 | 2018-10-24 01:22:09 -0700 | [diff] [blame] | 513 | UErrorCode& status) { |
Jungshik Shin | b318966 | 2017-11-07 11:18:34 -0800 | [diff] [blame] | 514 | int32_t length = 0; |
| 515 | if (quantity.isInfinite()) { |
| 516 | length += string.insert( |
Jungshik Shin | 42d5027 | 2018-10-24 01:22:09 -0700 | [diff] [blame] | 517 | length + index, |
Jungshik Shin | b318966 | 2017-11-07 11:18:34 -0800 | [diff] [blame] | 518 | micros.symbols->getSymbol(DecimalFormatSymbols::ENumberFormatSymbol::kInfinitySymbol), |
Frank Tang | f222396 | 2020-04-27 18:25:29 -0700 | [diff] [blame] | 519 | {UFIELD_CATEGORY_NUMBER, UNUM_INTEGER_FIELD}, |
Jungshik Shin | b318966 | 2017-11-07 11:18:34 -0800 | [diff] [blame] | 520 | status); |
| 521 | |
| 522 | } else if (quantity.isNaN()) { |
| 523 | length += string.insert( |
Jungshik Shin | 42d5027 | 2018-10-24 01:22:09 -0700 | [diff] [blame] | 524 | length + index, |
Jungshik Shin | b318966 | 2017-11-07 11:18:34 -0800 | [diff] [blame] | 525 | micros.symbols->getSymbol(DecimalFormatSymbols::ENumberFormatSymbol::kNaNSymbol), |
Frank Tang | f222396 | 2020-04-27 18:25:29 -0700 | [diff] [blame] | 526 | {UFIELD_CATEGORY_NUMBER, UNUM_INTEGER_FIELD}, |
Jungshik Shin | b318966 | 2017-11-07 11:18:34 -0800 | [diff] [blame] | 527 | status); |
| 528 | |
| 529 | } else { |
| 530 | // Add the integer digits |
Jungshik Shin | 42d5027 | 2018-10-24 01:22:09 -0700 | [diff] [blame] | 531 | length += writeIntegerDigits(micros, quantity, string, length + index, status); |
Jungshik Shin | b318966 | 2017-11-07 11:18:34 -0800 | [diff] [blame] | 532 | |
| 533 | // Add the decimal point |
| 534 | if (quantity.getLowerDisplayMagnitude() < 0 || micros.decimal == UNUM_DECIMAL_SEPARATOR_ALWAYS) { |
Frank Tang | 3e05d9d | 2021-11-08 14:04:04 -0800 | [diff] [blame] | 535 | if (!micros.currencyAsDecimal.isBogus()) { |
| 536 | length += string.insert( |
Jungshik Shin | 42d5027 | 2018-10-24 01:22:09 -0700 | [diff] [blame] | 537 | length + index, |
Frank Tang | 3e05d9d | 2021-11-08 14:04:04 -0800 | [diff] [blame] | 538 | micros.currencyAsDecimal, |
| 539 | {UFIELD_CATEGORY_NUMBER, UNUM_CURRENCY_FIELD}, |
| 540 | status); |
| 541 | } else if (micros.useCurrency) { |
| 542 | length += string.insert( |
| 543 | length + index, |
| 544 | micros.symbols->getSymbol( |
| 545 | DecimalFormatSymbols::ENumberFormatSymbol::kMonetarySeparatorSymbol), |
Frank Tang | f222396 | 2020-04-27 18:25:29 -0700 | [diff] [blame] | 546 | {UFIELD_CATEGORY_NUMBER, UNUM_DECIMAL_SEPARATOR_FIELD}, |
Jungshik Shin | b318966 | 2017-11-07 11:18:34 -0800 | [diff] [blame] | 547 | status); |
Frank Tang | 3e05d9d | 2021-11-08 14:04:04 -0800 | [diff] [blame] | 548 | } else { |
| 549 | length += string.insert( |
| 550 | length + index, |
| 551 | micros.symbols->getSymbol( |
| 552 | DecimalFormatSymbols::ENumberFormatSymbol::kDecimalSeparatorSymbol), |
| 553 | {UFIELD_CATEGORY_NUMBER, UNUM_DECIMAL_SEPARATOR_FIELD}, |
| 554 | status); |
| 555 | } |
Jungshik Shin | b318966 | 2017-11-07 11:18:34 -0800 | [diff] [blame] | 556 | } |
| 557 | |
| 558 | // Add the fraction digits |
Jungshik Shin | 42d5027 | 2018-10-24 01:22:09 -0700 | [diff] [blame] | 559 | length += writeFractionDigits(micros, quantity, string, length + index, status); |
Frank Tang | f222396 | 2020-04-27 18:25:29 -0700 | [diff] [blame] | 560 | |
| 561 | if (length == 0) { |
| 562 | // Force output of the digit for value 0 |
| 563 | length += utils::insertDigitFromSymbols( |
| 564 | string, |
| 565 | index, |
| 566 | 0, |
| 567 | *micros.symbols, |
| 568 | {UFIELD_CATEGORY_NUMBER, UNUM_INTEGER_FIELD}, |
| 569 | status); |
| 570 | } |
Jungshik Shin | b318966 | 2017-11-07 11:18:34 -0800 | [diff] [blame] | 571 | } |
| 572 | |
| 573 | return length; |
| 574 | } |
| 575 | |
Jungshik Shin | a9a2bd3 | 2018-07-07 03:36:01 -0700 | [diff] [blame] | 576 | int32_t NumberFormatterImpl::writeIntegerDigits(const MicroProps& micros, DecimalQuantity& quantity, |
Frank Tang | b869661 | 2019-10-25 14:58:21 -0700 | [diff] [blame] | 577 | FormattedStringBuilder& string, int32_t index, |
Jungshik Shin | 42d5027 | 2018-10-24 01:22:09 -0700 | [diff] [blame] | 578 | UErrorCode& status) { |
Jungshik Shin | b318966 | 2017-11-07 11:18:34 -0800 | [diff] [blame] | 579 | int length = 0; |
| 580 | int integerCount = quantity.getUpperDisplayMagnitude() + 1; |
| 581 | for (int i = 0; i < integerCount; i++) { |
| 582 | // Add grouping separator |
| 583 | if (micros.grouping.groupAtPosition(i, quantity)) { |
| 584 | length += string.insert( |
Jungshik Shin | 42d5027 | 2018-10-24 01:22:09 -0700 | [diff] [blame] | 585 | index, |
Jungshik Shin | b318966 | 2017-11-07 11:18:34 -0800 | [diff] [blame] | 586 | micros.useCurrency ? micros.symbols->getSymbol( |
| 587 | DecimalFormatSymbols::ENumberFormatSymbol::kMonetaryGroupingSeparatorSymbol) |
| 588 | : micros.symbols->getSymbol( |
| 589 | DecimalFormatSymbols::ENumberFormatSymbol::kGroupingSeparatorSymbol), |
Frank Tang | f222396 | 2020-04-27 18:25:29 -0700 | [diff] [blame] | 590 | {UFIELD_CATEGORY_NUMBER, UNUM_GROUPING_SEPARATOR_FIELD}, |
Jungshik Shin | b318966 | 2017-11-07 11:18:34 -0800 | [diff] [blame] | 591 | status); |
| 592 | } |
| 593 | |
| 594 | // Get and append the next digit value |
| 595 | int8_t nextDigit = quantity.getDigit(i); |
Jungshik Shin | a9a2bd3 | 2018-07-07 03:36:01 -0700 | [diff] [blame] | 596 | length += utils::insertDigitFromSymbols( |
Frank Tang | f222396 | 2020-04-27 18:25:29 -0700 | [diff] [blame] | 597 | string, |
| 598 | index, |
| 599 | nextDigit, |
| 600 | *micros.symbols, |
| 601 | {UFIELD_CATEGORY_NUMBER, |
| 602 | UNUM_INTEGER_FIELD}, |
| 603 | status); |
Jungshik Shin | b318966 | 2017-11-07 11:18:34 -0800 | [diff] [blame] | 604 | } |
| 605 | return length; |
| 606 | } |
| 607 | |
Jungshik Shin | a9a2bd3 | 2018-07-07 03:36:01 -0700 | [diff] [blame] | 608 | int32_t NumberFormatterImpl::writeFractionDigits(const MicroProps& micros, DecimalQuantity& quantity, |
Frank Tang | b869661 | 2019-10-25 14:58:21 -0700 | [diff] [blame] | 609 | FormattedStringBuilder& string, int32_t index, |
Jungshik Shin | 42d5027 | 2018-10-24 01:22:09 -0700 | [diff] [blame] | 610 | UErrorCode& status) { |
Jungshik Shin | b318966 | 2017-11-07 11:18:34 -0800 | [diff] [blame] | 611 | int length = 0; |
| 612 | int fractionCount = -quantity.getLowerDisplayMagnitude(); |
| 613 | for (int i = 0; i < fractionCount; i++) { |
| 614 | // Get and append the next digit value |
| 615 | int8_t nextDigit = quantity.getDigit(-i - 1); |
Jungshik Shin | a9a2bd3 | 2018-07-07 03:36:01 -0700 | [diff] [blame] | 616 | length += utils::insertDigitFromSymbols( |
Frank Tang | f222396 | 2020-04-27 18:25:29 -0700 | [diff] [blame] | 617 | string, |
| 618 | length + index, |
| 619 | nextDigit, |
| 620 | *micros.symbols, |
| 621 | {UFIELD_CATEGORY_NUMBER, UNUM_FRACTION_FIELD}, |
| 622 | status); |
Jungshik Shin | b318966 | 2017-11-07 11:18:34 -0800 | [diff] [blame] | 623 | } |
| 624 | return length; |
| 625 | } |
| 626 | |
| 627 | #endif /* #if !UCONFIG_NO_FORMATTING */ |