diff options
Diffstat (limited to 'deps/node/deps/icu-small/source/i18n/number_mapper.cpp')
-rw-r--r-- | deps/node/deps/icu-small/source/i18n/number_mapper.cpp | 508 |
1 files changed, 0 insertions, 508 deletions
diff --git a/deps/node/deps/icu-small/source/i18n/number_mapper.cpp b/deps/node/deps/icu-small/source/i18n/number_mapper.cpp deleted file mode 100644 index 2c9a8e51..00000000 --- a/deps/node/deps/icu-small/source/i18n/number_mapper.cpp +++ /dev/null @@ -1,508 +0,0 @@ -// © 2018 and later: Unicode, Inc. and others. -// License & terms of use: http://www.unicode.org/copyright.html - -#include "unicode/utypes.h" - -#if !UCONFIG_NO_FORMATTING - -// Allow implicit conversion from char16_t* to UnicodeString for this file: -// Helpful in toString methods and elsewhere. -#define UNISTR_FROM_STRING_EXPLICIT - -#include "number_mapper.h" -#include "number_patternstring.h" -#include "unicode/errorcode.h" -#include "number_utils.h" -#include "number_currencysymbols.h" - -using namespace icu; -using namespace icu::number; -using namespace icu::number::impl; - - -UnlocalizedNumberFormatter NumberPropertyMapper::create(const DecimalFormatProperties& properties, - const DecimalFormatSymbols& symbols, - DecimalFormatWarehouse& warehouse, - UErrorCode& status) { - return NumberFormatter::with().macros(oldToNew(properties, symbols, warehouse, nullptr, status)); -} - -UnlocalizedNumberFormatter NumberPropertyMapper::create(const DecimalFormatProperties& properties, - const DecimalFormatSymbols& symbols, - DecimalFormatWarehouse& warehouse, - DecimalFormatProperties& exportedProperties, - UErrorCode& status) { - return NumberFormatter::with().macros( - oldToNew( - properties, symbols, warehouse, &exportedProperties, status)); -} - -MacroProps NumberPropertyMapper::oldToNew(const DecimalFormatProperties& properties, - const DecimalFormatSymbols& symbols, - DecimalFormatWarehouse& warehouse, - DecimalFormatProperties* exportedProperties, - UErrorCode& status) { - MacroProps macros; - Locale locale = symbols.getLocale(); - - ///////////// - // SYMBOLS // - ///////////// - - macros.symbols.setTo(symbols); - - ////////////////// - // PLURAL RULES // - ////////////////// - - if (!properties.currencyPluralInfo.fPtr.isNull()) { - macros.rules = properties.currencyPluralInfo.fPtr->getPluralRules(); - } - - ///////////// - // AFFIXES // - ///////////// - - AffixPatternProvider* affixProvider; - if (properties.currencyPluralInfo.fPtr.isNull()) { - warehouse.currencyPluralInfoAPP.setToBogus(); - warehouse.propertiesAPP.setTo(properties, status); - affixProvider = &warehouse.propertiesAPP; - } else { - warehouse.currencyPluralInfoAPP.setTo(*properties.currencyPluralInfo.fPtr, properties, status); - warehouse.propertiesAPP.setToBogus(); - affixProvider = &warehouse.currencyPluralInfoAPP; - } - macros.affixProvider = affixProvider; - - /////////// - // UNITS // - /////////// - - bool useCurrency = ( - !properties.currency.isNull() || !properties.currencyPluralInfo.fPtr.isNull() || - !properties.currencyUsage.isNull() || affixProvider->hasCurrencySign()); - CurrencyUnit currency = resolveCurrency(properties, locale, status); - UCurrencyUsage currencyUsage = properties.currencyUsage.getOrDefault(UCURR_USAGE_STANDARD); - if (useCurrency) { - // NOTE: Slicing is OK. - macros.unit = currency; // NOLINT - } - warehouse.currencySymbols = {currency, locale, symbols, status}; - macros.currencySymbols = &warehouse.currencySymbols; - - /////////////////////// - // ROUNDING STRATEGY // - /////////////////////// - - int32_t maxInt = properties.maximumIntegerDigits; - int32_t minInt = properties.minimumIntegerDigits; - int32_t maxFrac = properties.maximumFractionDigits; - int32_t minFrac = properties.minimumFractionDigits; - int32_t minSig = properties.minimumSignificantDigits; - int32_t maxSig = properties.maximumSignificantDigits; - double roundingIncrement = properties.roundingIncrement; - RoundingMode roundingMode = properties.roundingMode.getOrDefault(UNUM_ROUND_HALFEVEN); - bool explicitMinMaxFrac = minFrac != -1 || maxFrac != -1; - bool explicitMinMaxSig = minSig != -1 || maxSig != -1; - // Resolve min/max frac for currencies, required for the validation logic and for when minFrac or - // maxFrac was - // set (but not both) on a currency instance. - // NOTE: Increments are handled in "Precision.constructCurrency()". - if (useCurrency && (minFrac == -1 || maxFrac == -1)) { - int32_t digits = ucurr_getDefaultFractionDigitsForUsage( - currency.getISOCurrency(), currencyUsage, &status); - if (minFrac == -1 && maxFrac == -1) { - minFrac = digits; - maxFrac = digits; - } else if (minFrac == -1) { - minFrac = std::min(maxFrac, digits); - } else /* if (maxFrac == -1) */ { - maxFrac = std::max(minFrac, digits); - } - } - // Validate min/max int/frac. - // For backwards compatibility, minimum overrides maximum if the two conflict. - // The following logic ensures that there is always a minimum of at least one digit. - if (minInt == 0 && maxFrac != 0) { - // Force a digit after the decimal point. - minFrac = minFrac <= 0 ? 1 : minFrac; - maxFrac = maxFrac < 0 ? -1 : maxFrac < minFrac ? minFrac : maxFrac; - minInt = 0; - maxInt = maxInt < 0 ? -1 : maxInt > kMaxIntFracSig ? -1 : maxInt; - } else { - // Force a digit before the decimal point. - minFrac = minFrac < 0 ? 0 : minFrac; - maxFrac = maxFrac < 0 ? -1 : maxFrac < minFrac ? minFrac : maxFrac; - minInt = minInt <= 0 ? 1 : minInt > kMaxIntFracSig ? 1 : minInt; - maxInt = maxInt < 0 ? -1 : maxInt < minInt ? minInt : maxInt > kMaxIntFracSig ? -1 : maxInt; - } - Precision precision; - if (!properties.currencyUsage.isNull()) { - precision = Precision::constructCurrency(currencyUsage).withCurrency(currency); - } else if (roundingIncrement != 0.0) { - precision = Precision::constructIncrement(roundingIncrement, minFrac); - } else if (explicitMinMaxSig) { - minSig = minSig < 1 ? 1 : minSig > kMaxIntFracSig ? kMaxIntFracSig : minSig; - maxSig = maxSig < 0 ? kMaxIntFracSig : maxSig < minSig ? minSig : maxSig > kMaxIntFracSig - ? kMaxIntFracSig : maxSig; - precision = Precision::constructSignificant(minSig, maxSig); - } else if (explicitMinMaxFrac) { - precision = Precision::constructFraction(minFrac, maxFrac); - } else if (useCurrency) { - precision = Precision::constructCurrency(currencyUsage); - } - if (!precision.isBogus()) { - precision = precision.withMode(roundingMode); - macros.precision = precision; - } - - /////////////////// - // INTEGER WIDTH // - /////////////////// - - macros.integerWidth = IntegerWidth( - static_cast<digits_t>(minInt), - static_cast<digits_t>(maxInt), - properties.formatFailIfMoreThanMaxDigits); - - /////////////////////// - // GROUPING STRATEGY // - /////////////////////// - - macros.grouper = Grouper::forProperties(properties); - - ///////////// - // PADDING // - ///////////// - - if (properties.formatWidth != -1) { - macros.padder = Padder::forProperties(properties); - } - - /////////////////////////////// - // DECIMAL MARK ALWAYS SHOWN // - /////////////////////////////// - - macros.decimal = properties.decimalSeparatorAlwaysShown ? UNUM_DECIMAL_SEPARATOR_ALWAYS - : UNUM_DECIMAL_SEPARATOR_AUTO; - - /////////////////////// - // SIGN ALWAYS SHOWN // - /////////////////////// - - macros.sign = properties.signAlwaysShown ? UNUM_SIGN_ALWAYS : UNUM_SIGN_AUTO; - - ///////////////////////// - // SCIENTIFIC NOTATION // - ///////////////////////// - - if (properties.minimumExponentDigits != -1) { - // Scientific notation is required. - // This whole section feels like a hack, but it is needed for regression tests. - // The mapping from property bag to scientific notation is nontrivial due to LDML rules. - if (maxInt > 8) { - // But #13110: The maximum of 8 digits has unknown origins and is not in the spec. - // If maxInt is greater than 8, it is set to minInt, even if minInt is greater than 8. - maxInt = minInt; - macros.integerWidth = IntegerWidth::zeroFillTo(minInt).truncateAt(maxInt); - } else if (maxInt > minInt && minInt > 1) { - // Bug #13289: if maxInt > minInt > 1, then minInt should be 1. - minInt = 1; - macros.integerWidth = IntegerWidth::zeroFillTo(minInt).truncateAt(maxInt); - } - int engineering = maxInt < 0 ? -1 : maxInt; - macros.notation = ScientificNotation( - // Engineering interval: - static_cast<int8_t>(engineering), - // Enforce minimum integer digits (for patterns like "000.00E0"): - (engineering == minInt), - // Minimum exponent digits: - static_cast<digits_t>(properties.minimumExponentDigits), - // Exponent sign always shown: - properties.exponentSignAlwaysShown ? UNUM_SIGN_ALWAYS : UNUM_SIGN_AUTO); - // Scientific notation also involves overriding the rounding mode. - // TODO: Overriding here is a bit of a hack. Should this logic go earlier? - if (macros.precision.fType == Precision::PrecisionType::RND_FRACTION) { - // For the purposes of rounding, get the original min/max int/frac, since the local - // variables have been manipulated for display purposes. - int maxInt_ = properties.maximumIntegerDigits; - int minInt_ = properties.minimumIntegerDigits; - int minFrac_ = properties.minimumFractionDigits; - int maxFrac_ = properties.maximumFractionDigits; - if (minInt_ == 0 && maxFrac_ == 0) { - // Patterns like "#E0" and "##E0", which mean no rounding! - macros.precision = Precision::unlimited().withMode(roundingMode); - } else if (minInt_ == 0 && minFrac_ == 0) { - // Patterns like "#.##E0" (no zeros in the mantissa), which mean round to maxFrac+1 - macros.precision = Precision::constructSignificant(1, maxFrac_ + 1).withMode(roundingMode); - } else { - int maxSig_ = minInt_ + maxFrac_; - // Bug #20058: if maxInt_ > minInt_ > 1, then minInt_ should be 1. - if (maxInt_ > minInt_ && minInt_ > 1) { - minInt_ = 1; - } - int minSig_ = minInt_ + minFrac_; - // To avoid regression, maxSig is not reset when minInt_ set to 1. - // TODO: Reset maxSig_ = 1 + minFrac_ to follow the spec. - macros.precision = Precision::constructSignificant(minSig_, maxSig_).withMode(roundingMode); - } - } - } - - ////////////////////// - // COMPACT NOTATION // - ////////////////////// - - if (!properties.compactStyle.isNull()) { - if (properties.compactStyle.getNoError() == UNumberCompactStyle::UNUM_LONG) { - macros.notation = Notation::compactLong(); - } else { - macros.notation = Notation::compactShort(); - } - // Do not forward the affix provider. - macros.affixProvider = nullptr; - } - - ///////////////// - // MULTIPLIERS // - ///////////////// - - macros.scale = scaleFromProperties(properties); - - ////////////////////// - // PROPERTY EXPORTS // - ////////////////////// - - if (exportedProperties != nullptr) { - - exportedProperties->currency = currency; - exportedProperties->roundingMode = roundingMode; - exportedProperties->minimumIntegerDigits = minInt; - exportedProperties->maximumIntegerDigits = maxInt == -1 ? INT32_MAX : maxInt; - - Precision rounding_; - if (precision.fType == Precision::PrecisionType::RND_CURRENCY) { - rounding_ = precision.withCurrency(currency, status); - } else { - rounding_ = precision; - } - int minFrac_ = minFrac; - int maxFrac_ = maxFrac; - int minSig_ = minSig; - int maxSig_ = maxSig; - double increment_ = 0.0; - if (rounding_.fType == Precision::PrecisionType::RND_FRACTION) { - minFrac_ = rounding_.fUnion.fracSig.fMinFrac; - maxFrac_ = rounding_.fUnion.fracSig.fMaxFrac; - } else if (rounding_.fType == Precision::PrecisionType::RND_INCREMENT) { - increment_ = rounding_.fUnion.increment.fIncrement; - minFrac_ = rounding_.fUnion.increment.fMinFrac; - maxFrac_ = rounding_.fUnion.increment.fMinFrac; - } else if (rounding_.fType == Precision::PrecisionType::RND_SIGNIFICANT) { - minSig_ = rounding_.fUnion.fracSig.fMinSig; - maxSig_ = rounding_.fUnion.fracSig.fMaxSig; - } - - exportedProperties->minimumFractionDigits = minFrac_; - exportedProperties->maximumFractionDigits = maxFrac_; - exportedProperties->minimumSignificantDigits = minSig_; - exportedProperties->maximumSignificantDigits = maxSig_; - exportedProperties->roundingIncrement = increment_; - } - - return macros; -} - - -void PropertiesAffixPatternProvider::setTo(const DecimalFormatProperties& properties, UErrorCode&) { - fBogus = false; - - // There are two ways to set affixes in DecimalFormat: via the pattern string (applyPattern), and via the - // explicit setters (setPositivePrefix and friends). The way to resolve the settings is as follows: - // - // 1) If the explicit setting is present for the field, use it. - // 2) Otherwise, follows UTS 35 rules based on the pattern string. - // - // Importantly, the explicit setters affect only the one field they override. If you set the positive - // prefix, that should not affect the negative prefix. Since it is impossible for the user of this class - // to know whether the origin for a string was the override or the pattern, we have to say that we always - // have a negative subpattern and perform all resolution logic here. - - // Convenience: Extract the properties into local variables. - // Variables are named with three chars: [p/n][p/s][o/p] - // [p/n] => p for positive, n for negative - // [p/s] => p for prefix, s for suffix - // [o/p] => o for escaped custom override string, p for pattern string - UnicodeString ppo = AffixUtils::escape(properties.positivePrefix); - UnicodeString pso = AffixUtils::escape(properties.positiveSuffix); - UnicodeString npo = AffixUtils::escape(properties.negativePrefix); - UnicodeString nso = AffixUtils::escape(properties.negativeSuffix); - const UnicodeString& ppp = properties.positivePrefixPattern; - const UnicodeString& psp = properties.positiveSuffixPattern; - const UnicodeString& npp = properties.negativePrefixPattern; - const UnicodeString& nsp = properties.negativeSuffixPattern; - - if (!properties.positivePrefix.isBogus()) { - posPrefix = ppo; - } else if (!ppp.isBogus()) { - posPrefix = ppp; - } else { - // UTS 35: Default positive prefix is empty string. - posPrefix = u""; - } - - if (!properties.positiveSuffix.isBogus()) { - posSuffix = pso; - } else if (!psp.isBogus()) { - posSuffix = psp; - } else { - // UTS 35: Default positive suffix is empty string. - posSuffix = u""; - } - - if (!properties.negativePrefix.isBogus()) { - negPrefix = npo; - } else if (!npp.isBogus()) { - negPrefix = npp; - } else { - // UTS 35: Default negative prefix is "-" with positive prefix. - // Important: We prepend the "-" to the pattern, not the override! - negPrefix = ppp.isBogus() ? u"-" : u"-" + ppp; - } - - if (!properties.negativeSuffix.isBogus()) { - negSuffix = nso; - } else if (!nsp.isBogus()) { - negSuffix = nsp; - } else { - // UTS 35: Default negative prefix is the positive prefix. - negSuffix = psp.isBogus() ? u"" : psp; - } -} - -char16_t PropertiesAffixPatternProvider::charAt(int flags, int i) const { - return getStringInternal(flags).charAt(i); -} - -int PropertiesAffixPatternProvider::length(int flags) const { - return getStringInternal(flags).length(); -} - -UnicodeString PropertiesAffixPatternProvider::getString(int32_t flags) const { - return getStringInternal(flags); -} - -const UnicodeString& PropertiesAffixPatternProvider::getStringInternal(int32_t flags) const { - bool prefix = (flags & AFFIX_PREFIX) != 0; - bool negative = (flags & AFFIX_NEGATIVE_SUBPATTERN) != 0; - if (prefix && negative) { - return negPrefix; - } else if (prefix) { - return posPrefix; - } else if (negative) { - return negSuffix; - } else { - return posSuffix; - } -} - -bool PropertiesAffixPatternProvider::positiveHasPlusSign() const { - // TODO: Change the internal APIs to propagate out the error? - ErrorCode localStatus; - return AffixUtils::containsType(posPrefix, TYPE_PLUS_SIGN, localStatus) || - AffixUtils::containsType(posSuffix, TYPE_PLUS_SIGN, localStatus); -} - -bool PropertiesAffixPatternProvider::hasNegativeSubpattern() const { - // See comments in the constructor for more information on why this is always true. - return true; -} - -bool PropertiesAffixPatternProvider::negativeHasMinusSign() const { - ErrorCode localStatus; - return AffixUtils::containsType(negPrefix, TYPE_MINUS_SIGN, localStatus) || - AffixUtils::containsType(negSuffix, TYPE_MINUS_SIGN, localStatus); -} - -bool PropertiesAffixPatternProvider::hasCurrencySign() const { - ErrorCode localStatus; - return AffixUtils::hasCurrencySymbols(posPrefix, localStatus) || - AffixUtils::hasCurrencySymbols(posSuffix, localStatus) || - AffixUtils::hasCurrencySymbols(negPrefix, localStatus) || - AffixUtils::hasCurrencySymbols(negSuffix, localStatus); -} - -bool PropertiesAffixPatternProvider::containsSymbolType(AffixPatternType type, UErrorCode& status) const { - return AffixUtils::containsType(posPrefix, type, status) || - AffixUtils::containsType(posSuffix, type, status) || - AffixUtils::containsType(negPrefix, type, status) || - AffixUtils::containsType(negSuffix, type, status); -} - -bool PropertiesAffixPatternProvider::hasBody() const { - return true; -} - - -void CurrencyPluralInfoAffixProvider::setTo(const CurrencyPluralInfo& cpi, - const DecimalFormatProperties& properties, - UErrorCode& status) { - // We need to use a PropertiesAffixPatternProvider, not the simpler version ParsedPatternInfo, - // because user-specified affix overrides still need to work. - fBogus = false; - DecimalFormatProperties pluralProperties(properties); - for (int32_t plural = 0; plural < StandardPlural::COUNT; plural++) { - const char* keyword = StandardPlural::getKeyword(static_cast<StandardPlural::Form>(plural)); - UnicodeString patternString; - patternString = cpi.getCurrencyPluralPattern(keyword, patternString); - PatternParser::parseToExistingProperties( - patternString, - pluralProperties, - IGNORE_ROUNDING_NEVER, - status); - affixesByPlural[plural].setTo(pluralProperties, status); - } -} - -char16_t CurrencyPluralInfoAffixProvider::charAt(int32_t flags, int32_t i) const { - int32_t pluralOrdinal = (flags & AFFIX_PLURAL_MASK); - return affixesByPlural[pluralOrdinal].charAt(flags, i); -} - -int32_t CurrencyPluralInfoAffixProvider::length(int32_t flags) const { - int32_t pluralOrdinal = (flags & AFFIX_PLURAL_MASK); - return affixesByPlural[pluralOrdinal].length(flags); -} - -UnicodeString CurrencyPluralInfoAffixProvider::getString(int32_t flags) const { - int32_t pluralOrdinal = (flags & AFFIX_PLURAL_MASK); - return affixesByPlural[pluralOrdinal].getString(flags); -} - -bool CurrencyPluralInfoAffixProvider::positiveHasPlusSign() const { - return affixesByPlural[StandardPlural::OTHER].positiveHasPlusSign(); -} - -bool CurrencyPluralInfoAffixProvider::hasNegativeSubpattern() const { - return affixesByPlural[StandardPlural::OTHER].hasNegativeSubpattern(); -} - -bool CurrencyPluralInfoAffixProvider::negativeHasMinusSign() const { - return affixesByPlural[StandardPlural::OTHER].negativeHasMinusSign(); -} - -bool CurrencyPluralInfoAffixProvider::hasCurrencySign() const { - return affixesByPlural[StandardPlural::OTHER].hasCurrencySign(); -} - -bool CurrencyPluralInfoAffixProvider::containsSymbolType(AffixPatternType type, UErrorCode& status) const { - return affixesByPlural[StandardPlural::OTHER].containsSymbolType(type, status); -} - -bool CurrencyPluralInfoAffixProvider::hasBody() const { - return affixesByPlural[StandardPlural::OTHER].hasBody(); -} - - -#endif /* #if !UCONFIG_NO_FORMATTING */ |