Exemplo n.º 1
0
void CompactHandler::processQuantity(DecimalQuantity &quantity, MicroProps &micros,
                                     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();
}
Exemplo n.º 2
0
void MutablePatternModifier::processQuantity(DecimalQuantity &fq, MicroProps &micros,
                                             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;
}
Exemplo n.º 3
0
void ScientificHandler::processQuantity(DecimalQuantity &quantity, MicroProps &micros,
                                        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();
}
Exemplo n.º 4
0
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;
}
Exemplo n.º 5
0
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;
}