// © 2017 and later: Unicode, Inc. and others. // License & terms of use: http://www.unicode.org/copyright.html #include "unicode/utypes.h" #if !UCONFIG_NO_FORMATTING #include "unicode/numberformatter.h" #include "unicode/simplenumberformatter.h" #include "number_formatimpl.h" #include "number_utils.h" #include "number_patternmodifier.h" #include "number_utypes.h" using namespace icu; using namespace icu::number; using namespace icu::number::impl; SimpleNumber SimpleNumber::forInt64(int64_t value, UErrorCode& status) { if (U_FAILURE(status)) { return SimpleNumber(); } auto results = new UFormattedNumberData(); if (results == nullptr) { status = U_MEMORY_ALLOCATION_ERROR; return SimpleNumber(); } results->quantity.setToLong(value); return SimpleNumber(results, status); } SimpleNumber::SimpleNumber(UFormattedNumberData* data, UErrorCode& status) : fData(data) { if (U_FAILURE(status)) { return; } if (fData == nullptr) { status = U_ILLEGAL_ARGUMENT_ERROR; return; } if (fData->quantity.isNegative()) { fSign = UNUM_SIMPLE_NUMBER_MINUS_SIGN; } else { fSign = UNUM_SIMPLE_NUMBER_NO_SIGN; } } void SimpleNumber::cleanup() { delete fData; fData = nullptr; } void SimpleNumber::multiplyByPowerOfTen(int32_t power, UErrorCode& status) { if (U_FAILURE(status)) { return; } if (fData == nullptr) { status = U_INVALID_STATE_ERROR; return; } fData->quantity.adjustMagnitude(power); } void SimpleNumber::roundTo(int32_t position, UNumberFormatRoundingMode roundingMode, UErrorCode& status) { if (U_FAILURE(status)) { return; } if (fData == nullptr) { status = U_INVALID_STATE_ERROR; return; } fData->quantity.roundToMagnitude(position, roundingMode, status); } void SimpleNumber::setMinimumIntegerDigits(uint32_t position, UErrorCode& status) { if (U_FAILURE(status)) { return; } if (fData == nullptr) { status = U_INVALID_STATE_ERROR; return; } fData->quantity.setMinInteger(position); } void SimpleNumber::setMinimumFractionDigits(uint32_t position, UErrorCode& status) { if (U_FAILURE(status)) { return; } if (fData == nullptr) { status = U_INVALID_STATE_ERROR; return; } fData->quantity.setMinFraction(position); } void SimpleNumber::truncateStart(uint32_t position, UErrorCode& status) { if (U_FAILURE(status)) { return; } if (fData == nullptr) { status = U_INVALID_STATE_ERROR; return; } fData->quantity.applyMaxInteger(position); } void SimpleNumber::setSign(USimpleNumberSign sign, UErrorCode& status) { if (U_FAILURE(status)) { return; } if (fData == nullptr) { status = U_INVALID_STATE_ERROR; return; } fSign = sign; } void SimpleNumberFormatter::cleanup() { delete fOwnedSymbols; delete fMicros; delete fPatternModifier; fOwnedSymbols = nullptr; fMicros = nullptr; fPatternModifier = nullptr; } SimpleNumberFormatter SimpleNumberFormatter::forLocale(const icu::Locale &locale, UErrorCode &status) { return SimpleNumberFormatter::forLocaleAndGroupingStrategy(locale, UNUM_GROUPING_AUTO, status); } SimpleNumberFormatter SimpleNumberFormatter::forLocaleAndGroupingStrategy( const icu::Locale &locale, UNumberGroupingStrategy groupingStrategy, UErrorCode &status) { SimpleNumberFormatter retval; retval.fOwnedSymbols = new DecimalFormatSymbols(locale, status); if (U_FAILURE(status)) { return retval; } if (retval.fOwnedSymbols == nullptr) { status = U_MEMORY_ALLOCATION_ERROR; return retval; } retval.initialize(locale, *retval.fOwnedSymbols, groupingStrategy, status); return retval; } SimpleNumberFormatter SimpleNumberFormatter::forLocaleAndSymbolsAndGroupingStrategy( const icu::Locale &locale, const DecimalFormatSymbols &symbols, UNumberGroupingStrategy groupingStrategy, UErrorCode &status) { SimpleNumberFormatter retval; retval.initialize(locale, symbols, groupingStrategy, status); return retval; } void SimpleNumberFormatter::initialize( const icu::Locale &locale, const DecimalFormatSymbols &symbols, UNumberGroupingStrategy groupingStrategy, UErrorCode &status) { if (U_FAILURE(status)) { return; } fMicros = new SimpleMicroProps(); if (fMicros == nullptr) { status = U_MEMORY_ALLOCATION_ERROR; return; } fMicros->symbols = &symbols; auto pattern = utils::getPatternForStyle( locale, symbols.getNumberingSystemName(), CLDR_PATTERN_STYLE_DECIMAL, status); if (U_FAILURE(status)) { return; } ParsedPatternInfo patternInfo; PatternParser::parseToPatternInfo(UnicodeString(pattern), patternInfo, status); if (U_FAILURE(status)) { return; } auto grouper = Grouper::forStrategy(groupingStrategy); grouper.setLocaleData(patternInfo, locale); fMicros->grouping = grouper; MutablePatternModifier patternModifier(false); patternModifier.setPatternInfo(&patternInfo, kUndefinedField); patternModifier.setPatternAttributes(UNUM_SIGN_EXCEPT_ZERO, false, false); patternModifier.setSymbols(fMicros->symbols, {}, UNUM_UNIT_WIDTH_SHORT, nullptr, status); fPatternModifier = new AdoptingSignumModifierStore(patternModifier.createImmutableForPlural(StandardPlural::COUNT, status)); fGroupingStrategy = groupingStrategy; return; } FormattedNumber SimpleNumberFormatter::format(SimpleNumber value, UErrorCode &status) const { formatImpl(value.fData, value.fSign, status); // Do not save the results object if we encountered a failure. if (U_SUCCESS(status)) { auto temp = value.fData; value.fData = nullptr; return FormattedNumber(temp); } else { return FormattedNumber(status); } } void SimpleNumberFormatter::formatImpl(UFormattedNumberData* data, USimpleNumberSign sign, UErrorCode &status) const { if (U_FAILURE(status)) { return; } if (data == nullptr) { status = U_ILLEGAL_ARGUMENT_ERROR; return; } if (fPatternModifier == nullptr || fMicros == nullptr) { status = U_INVALID_STATE_ERROR; return; } Signum signum; if (sign == UNUM_SIMPLE_NUMBER_MINUS_SIGN) { signum = SIGNUM_NEG; } else if (sign == UNUM_SIMPLE_NUMBER_PLUS_SIGN) { signum = SIGNUM_POS; } else { signum = SIGNUM_POS_ZERO; } const Modifier* modifier = (*fPatternModifier)[signum]; auto length = NumberFormatterImpl::writeNumber( *fMicros, data->quantity, data->getStringRef(), 0, status); length += modifier->apply(data->getStringRef(), 0, length, status); data->getStringRef().writeTerminator(status); } #endif /* #if !UCONFIG_NO_FORMATTING */