void CompactHandler::processQuantity(DecimalQuantity &quantity, MicroProps µs, UErrorCode &status) const { parent->processQuantity(quantity, micros, status); if (U_FAILURE(status)) { return; } // Treat zero as if it had magnitude 0 int32_t magnitude; if (quantity.isZero()) { magnitude = 0; micros.rounder.apply(quantity, status); } else { // TODO: Revisit chooseMultiplierAndApply int32_t multiplier = micros.rounder.chooseMultiplierAndApply(quantity, data, status); magnitude = quantity.isZero() ? 0 : quantity.getMagnitude(); magnitude -= multiplier; } StandardPlural::Form plural = utils::getStandardPlural(rules, quantity); const UChar *patternString = data.getPattern(magnitude, plural); if (patternString == nullptr) { // Use the default (non-compact) modifier. // No need to take any action. } else if (safe) { // Safe code path. // Java uses a hash set here for O(1) lookup. C++ uses a linear search. // TODO: Benchmark this and maybe change to a binary search or hash table. int32_t i = 0; for (; i < precomputedModsLength; i++) { const CompactModInfo &info = precomputedMods[i]; if (u_strcmp(patternString, info.patternString) == 0) { info.mod->applyToMicros(micros, quantity); break; } } // It should be guaranteed that we found the entry. U_ASSERT(i < precomputedModsLength); } else { // Unsafe code path. // Overwrite the PatternInfo in the existing modMiddle. // C++ Note: Use unsafePatternInfo for proper lifecycle. ParsedPatternInfo &patternInfo = const_cast<CompactHandler *>(this)->unsafePatternInfo; PatternParser::parseToPatternInfo(UnicodeString(patternString), patternInfo, status); static_cast<MutablePatternModifier*>(const_cast<Modifier*>(micros.modMiddle)) ->setPatternInfo(&patternInfo); } // We already performed rounding. Do not perform it again. micros.rounder = RoundingImpl::passThrough(); }
void MutablePatternModifier::processQuantity(DecimalQuantity &fq, MicroProps µs, UErrorCode &status) const { parent->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.rounding.apply(copy, status); nonConstThis->setNumberProperties(fq.isNegative(), copy.getStandardPlural(rules)); } else { nonConstThis->setNumberProperties(fq.isNegative(), StandardPlural::Form::COUNT); } micros.modMiddle = this; }
void ScientificHandler::processQuantity(DecimalQuantity &quantity, MicroProps µs, UErrorCode &status) const { fParent->processQuantity(quantity, micros, status); if (U_FAILURE(status)) { return; } // Treat zero as if it had magnitude 0 int32_t exponent; if (quantity.isZero()) { if (fSettings.fRequireMinInt && micros.rounder.isSignificantDigits()) { // Show "00.000E0" on pattern "00.000E0" micros.rounder.apply(quantity, fSettings.fEngineeringInterval, status); exponent = 0; } else { micros.rounder.apply(quantity, status); exponent = 0; } } else { exponent = -micros.rounder.chooseMultiplierAndApply(quantity, *this, status); } // Use MicroProps's helper ScientificModifier and save it as the modInner. ScientificModifier &mod = micros.helpers.scientificModifier; mod.set(exponent, this); micros.modInner = &mod; // We already performed rounding. Do not perform it again. micros.rounder = RoundingImpl::passThrough(); }
int32_t NumberFormatterImpl::writeNumber(const MicroProps& micros, DecimalQuantity& quantity, NumberStringBuilder& string, UErrorCode& status) { int32_t length = 0; if (quantity.isInfinite()) { length += string.insert( length, micros.symbols->getSymbol(DecimalFormatSymbols::ENumberFormatSymbol::kInfinitySymbol), UNUM_INTEGER_FIELD, status); } else if (quantity.isNaN()) { length += string.insert( length, micros.symbols->getSymbol(DecimalFormatSymbols::ENumberFormatSymbol::kNaNSymbol), UNUM_INTEGER_FIELD, status); } else { // Add the integer digits length += writeIntegerDigits(micros, quantity, string, status); // Add the decimal point if (quantity.getLowerDisplayMagnitude() < 0 || micros.decimal == UNUM_DECIMAL_SEPARATOR_ALWAYS) { length += string.insert( length, micros.useCurrency ? micros.symbols->getSymbol( DecimalFormatSymbols::ENumberFormatSymbol::kMonetarySeparatorSymbol) : micros .symbols ->getSymbol( DecimalFormatSymbols::ENumberFormatSymbol::kDecimalSeparatorSymbol), UNUM_DECIMAL_SEPARATOR_FIELD, status); } // Add the fraction digits length += writeFractionDigits(micros, quantity, string, status); } return length; }
int32_t NumberFormatterImpl::writeIntegerDigits(const MicroProps& micros, DecimalQuantity& quantity, NumberStringBuilder& string, 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, micros.useCurrency ? micros.symbols->getSymbol( DecimalFormatSymbols::ENumberFormatSymbol::kMonetaryGroupingSeparatorSymbol) : micros.symbols->getSymbol( DecimalFormatSymbols::ENumberFormatSymbol::kGroupingSeparatorSymbol), UNUM_GROUPING_SEPARATOR_FIELD, status); } // 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); } return length; }