From 1a95c170d2bec74d4f44205f07bea3c49bc85811 Mon Sep 17 00:00:00 2001 From: Shane Carr Date: Thu, 15 Mar 2018 07:46:56 +0000 Subject: [PATCH] ICU-13634 Number property mapper is building. Currently there is a linker error. X-SVN-Rev: 41107 --- icu4c/source/i18n/number_grouping.cpp | 9 + icu4c/source/i18n/number_mapper.cpp | 298 +++++++++++++++++- icu4c/source/i18n/number_mapper.h | 102 +++++- icu4c/source/i18n/number_notation.cpp | 13 + icu4c/source/i18n/number_padding.cpp | 13 + icu4c/source/i18n/number_patternstring.cpp | 5 + icu4c/source/i18n/number_patternstring.h | 2 + icu4c/source/i18n/number_types.h | 4 + .../i18n/unicode/compactdecimalformat.h | 2 +- icu4c/source/i18n/unicode/decimfmt.h | 8 +- .../src/com/ibm/icu/impl/number/Padder.java | 6 + .../ibm/icu/number/NumberPropertyMapper.java | 10 +- 12 files changed, 451 insertions(+), 21 deletions(-) diff --git a/icu4c/source/i18n/number_grouping.cpp b/icu4c/source/i18n/number_grouping.cpp index 1f4a163d7bf..a77e505a221 100644 --- a/icu4c/source/i18n/number_grouping.cpp +++ b/icu4c/source/i18n/number_grouping.cpp @@ -51,6 +51,15 @@ Grouper Grouper::forStrategy(UGroupingStrategy grouping) { } } +Grouper Grouper::forProperties(const DecimalFormatProperties& properties) { + auto grouping1 = static_cast(properties.groupingSize); + auto grouping2 = static_cast(properties.secondaryGroupingSize); + auto minGrouping = static_cast(properties.minimumGroupingDigits); + grouping1 = grouping1 > 0 ? grouping1 : grouping2 > 0 ? grouping2 : grouping1; + grouping2 = grouping2 > 0 ? grouping2 : grouping1; + return {grouping1, grouping2, minGrouping}; +} + void Grouper::setLocaleData(const impl::ParsedPatternInfo &patternInfo, const Locale& locale) { if (fGrouping1 != -2 && fGrouping2 != -4) { return; diff --git a/icu4c/source/i18n/number_mapper.cpp b/icu4c/source/i18n/number_mapper.cpp index b1e596671dd..949f88aadd2 100644 --- a/icu4c/source/i18n/number_mapper.cpp +++ b/icu4c/source/i18n/number_mapper.cpp @@ -10,6 +10,7 @@ #define UNISTR_FROM_STRING_EXPLICIT #include "number_mapper.h" +#include "number_patternstring.h" using namespace icu; using namespace icu::number; @@ -18,13 +19,306 @@ 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 // + ////////////////// + + // TODO + + ///////////// + // AFFIXES // + ///////////// + + AffixPatternProvider* affixProvider; + if (properties.currencyPluralInfo.fPtr.isNull()) { + warehouse.currencyPluralInfoAPP.setToBogus(); + warehouse.propertiesAPP.setTo(properties); + affixProvider = &warehouse.propertiesAPP; + } else { + warehouse.currencyPluralInfoAPP.setTo(*properties.currencyPluralInfo.fPtr); + warehouse.propertiesAPP.setToBogus(); + affixProvider = &warehouse.currencyPluralInfoAPP; + } + macros.affixProvider = affixProvider; + + /////////// + // UNITS // + /////////// + + bool useCurrency = ( + !properties.currency.isNull() || !properties.currencyPluralInfo.fPtr.isNull() || + !properties.currencyUsage.isNull() || affixProvider->hasCurrencySign()); + // TODO: CustomSymbolCurrency + CurrencyUnit currency = {u"USD", status}; + UCurrencyUsage currencyUsage = properties.currencyUsage.getOrDefault(UCURR_USAGE_STANDARD); + if (useCurrency) { + // NOTE: Slicing is OK. + macros.unit = currency; // NOLINT + } + + /////////////////////// + // 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 "Rounder.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; + } + Rounder rounding; + if (!properties.currencyUsage.isNull()) { + rounding = Rounder::constructCurrency(currencyUsage).withCurrency(currency); + } else if (roundingIncrement != 0.0) { + rounding = Rounder::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; + rounding = Rounder::constructSignificant(minSig, maxSig); + } else if (explicitMinMaxFrac) { + rounding = Rounder::constructFraction(minFrac, maxFrac); + } else if (useCurrency) { + rounding = Rounder::constructCurrency(currencyUsage); + } + if (!rounding.isBogus()) { + rounding = rounding.withMode(roundingMode); + macros.rounder = rounding; + } + + /////////////////// + // INTEGER WIDTH // + /////////////////// + + macros.integerWidth = IntegerWidth::zeroFillTo(minInt).truncateAt(maxInt); + + /////////////////////// + // 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(engineering), + // Enforce minimum integer digits (for patterns like "000.00E0"): + (engineering == minInt), + // Minimum exponent digits: + static_cast(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.rounder.fType == Rounder::RounderType::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 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.rounder = Rounder::unlimited().withMode(roundingMode); + } else if (minInt_ == 0 && minFrac_ == 0) { + // Patterns like "#.##E0" (no zeros in the mantissa), which mean round to maxFrac+1 + macros.rounder = Rounder::constructSignificant(1, maxFrac_ + 1).withMode(roundingMode); + } else { + // All other scientific patterns, which mean round to minInt+maxFrac + macros.rounder = Rounder::constructSignificant(minInt_ + minFrac_, minInt_ + maxFrac_) + .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 // + ///////////////// + + if (properties.magnitudeMultiplier != 0) { + macros.multiplier = MultiplierImpl::magnitude(properties.magnitudeMultiplier); + } else if (properties.multiplier != 1) { + macros.multiplier = MultiplierImpl::integer(properties.multiplier); + } + + ////////////////////// + // PROPERTY EXPORTS // + ////////////////////// + + if (exportedProperties != nullptr) { + + exportedProperties->roundingMode = roundingMode; + exportedProperties->minimumIntegerDigits = minInt; + exportedProperties->maximumIntegerDigits = maxInt == -1 ? INT32_MAX : maxInt; + + Rounder rounding_; + if (rounding.fType == Rounder::RounderType::RND_CURRENCY) { + rounding_ = rounding.withCurrency(currency, status); + } else { + rounding_ = rounding; + } + int minFrac_ = minFrac; + int maxFrac_ = maxFrac; + int minSig_ = minSig; + int maxSig_ = maxSig; + double increment_ = 0.0; + if (rounding_.fType == Rounder::RounderType::RND_FRACTION) { + minFrac_ = rounding_.fUnion.fracSig.fMinFrac; + maxFrac_ = rounding_.fUnion.fracSig.fMaxFrac; + } else if (rounding_.fType == Rounder::RounderType::RND_INCREMENT) { + increment_ = rounding_.fUnion.increment.fIncrement; + minFrac_ = rounding_.fUnion.increment.fMinFrac; + maxFrac_ = rounding_.fUnion.increment.fMinFrac; + } else if (rounding_.fType == Rounder::RounderType::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) { + // TODO +} + +bool PropertiesAffixPatternProvider::hasBody() const { + return true; +} + + +void CurrencyPluralInfoAffixProvider::setTo(const CurrencyPluralInfo& cpi) { // TODO - status = U_UNSUPPORTED_ERROR; - return NumberFormatter::with(); } +bool CurrencyPluralInfoAffixProvider::hasBody() const { + return affixesByPlural[StandardPlural::OTHER].hasBody(); +} #endif /* #if !UCONFIG_NO_FORMATTING */ diff --git a/icu4c/source/i18n/number_mapper.h b/icu4c/source/i18n/number_mapper.h index c3960a665be..842b183fd53 100644 --- a/icu4c/source/i18n/number_mapper.h +++ b/icu4c/source/i18n/number_mapper.h @@ -8,11 +8,96 @@ #define __NUMBER_MAPPER_H__ #include "number_types.h" +#include "unicode/currpinf.h" +#include "standardplural.h" +#include "number_patternstring.h" U_NAMESPACE_BEGIN namespace number { namespace impl { +class PropertiesAffixPatternProvider : public AffixPatternProvider, public UMemory { + public: + bool isBogus() const; + + void setTo(const DecimalFormatProperties& properties); + + void setToBogus(); + + // AffixPatternProvider Methods: + + char16_t charAt(int flags, int i) const U_OVERRIDE; + + int length(int flags) const U_OVERRIDE; + + UnicodeString getString(int flags) const U_OVERRIDE; + + bool hasCurrencySign() const U_OVERRIDE; + + bool positiveHasPlusSign() const U_OVERRIDE; + + bool hasNegativeSubpattern() const U_OVERRIDE; + + bool negativeHasMinusSign() const U_OVERRIDE; + + bool containsSymbolType(AffixPatternType, UErrorCode&) const U_OVERRIDE; + + virtual bool hasBody() const U_OVERRIDE; + + private: + UnicodeString posPrefix; + UnicodeString posSuffix; + UnicodeString negPrefix; + UnicodeString negSuffix; + + bool fBogus{true}; +}; + + +class CurrencyPluralInfoAffixProvider : public AffixPatternProvider, public UMemory { + public: + bool isBogus() const; + + void setTo(const CurrencyPluralInfo& cpi); + + void setToBogus(); + + // AffixPatternProvider Methods: + + char16_t charAt(int flags, int i) const U_OVERRIDE; + + int length(int flags) const U_OVERRIDE; + + UnicodeString getString(int flags) const U_OVERRIDE; + + bool hasCurrencySign() const U_OVERRIDE; + + bool positiveHasPlusSign() const U_OVERRIDE; + + bool hasNegativeSubpattern() const U_OVERRIDE; + + bool negativeHasMinusSign() const U_OVERRIDE; + + bool containsSymbolType(AffixPatternType, UErrorCode&) const U_OVERRIDE; + + virtual bool hasBody() const U_OVERRIDE; + + private: + ParsedPatternInfo affixesByPlural[StandardPlural::COUNT]; + + bool fBogus{true}; +}; + + +/** + * A struct for ownership of a few objects needed for formatting. + */ +struct DecimalFormatWarehouse { + PropertiesAffixPatternProvider propertiesAPP; + CurrencyPluralInfoAffixProvider currencyPluralInfoAPP; +}; + + /** * Utilities for converting between a DecimalFormatProperties and a MacroProps. */ @@ -20,21 +105,16 @@ class NumberPropertyMapper { public: /** Convenience method to create a NumberFormatter directly from Properties. */ static UnlocalizedNumberFormatter create(const DecimalFormatProperties& properties, - const DecimalFormatSymbols& symbols, UErrorCode& status); + const DecimalFormatSymbols& symbols, + DecimalFormatWarehouse& warehouse, UErrorCode& status); /** Convenience method to create a NumberFormatter directly from Properties. */ static UnlocalizedNumberFormatter create(const DecimalFormatProperties& properties, const DecimalFormatSymbols& symbols, + DecimalFormatWarehouse& warehouse, DecimalFormatProperties& exportedProperties, UErrorCode& status); - /** - * Convenience method to create a NumberFormatter directly from a pattern string. Something like this - * could become public API if there is demand. - */ - static UnlocalizedNumberFormatter create(const UnicodeString& pattern, - const DecimalFormatSymbols& symbols, UErrorCode& status); - /** * Creates a new {@link MacroProps} object based on the content of a {@link DecimalFormatProperties} * object. In other words, maps Properties to MacroProps. This function is used by the @@ -49,9 +129,9 @@ class NumberPropertyMapper { * getters. * @return A new MacroProps containing all of the information in the Properties. */ - static void oldToNew(const DecimalFormatProperties& properties, const DecimalFormatSymbols& symbols, - DecimalFormatProperties& exportedProperties, MacroProps& output, - UErrorCode& status); + static MacroProps oldToNew(const DecimalFormatProperties& properties, + const DecimalFormatSymbols& symbols, DecimalFormatWarehouse& warehouse, + DecimalFormatProperties* exportedProperties, UErrorCode& status); }; diff --git a/icu4c/source/i18n/number_notation.cpp b/icu4c/source/i18n/number_notation.cpp index f4ad333354d..da61433b1c2 100644 --- a/icu4c/source/i18n/number_notation.cpp +++ b/icu4c/source/i18n/number_notation.cpp @@ -36,6 +36,19 @@ ScientificNotation Notation::engineering() { return {NTN_SCIENTIFIC, union_}; } +ScientificNotation::ScientificNotation(int8_t fEngineeringInterval, bool fRequireMinInt, + impl::digits_t fMinExponentDigits, + UNumberSignDisplay fExponentSignDisplay) { + ScientificSettings settings; + settings.fEngineeringInterval = fEngineeringInterval; + settings.fRequireMinInt = fRequireMinInt; + settings.fMinExponentDigits = fMinExponentDigits; + settings.fExponentSignDisplay = fExponentSignDisplay; + NotationUnion union_; + union_.scientific = settings; + *this = {NTN_SCIENTIFIC, union_}; +} + Notation Notation::compactShort() { NotationUnion union_; union_.compactStyle = CompactStyle::UNUM_SHORT; diff --git a/icu4c/source/i18n/number_padding.cpp b/icu4c/source/i18n/number_padding.cpp index b1db3490cd4..3c470df5045 100644 --- a/icu4c/source/i18n/number_padding.cpp +++ b/icu4c/source/i18n/number_padding.cpp @@ -8,6 +8,7 @@ #include "unicode/numberformatter.h" #include "number_types.h" #include "number_stringbuilder.h" +#include "number_decimfmtprops.h" using namespace icu; using namespace icu::number; @@ -15,6 +16,8 @@ using namespace icu::number::impl; namespace { +static UChar32 kFallbackPadChar = 0x0020; + int32_t addPaddingHelper(UChar32 paddingCp, int32_t requiredPadding, NumberStringBuilder &string, int32_t index, UErrorCode &status) { @@ -47,6 +50,16 @@ Padder Padder::codePoints(UChar32 cp, int32_t targetWidth, UNumberFormatPadPosit } } +Padder Padder::forProperties(const DecimalFormatProperties& properties) { + UChar32 padCp; + if (properties.padString.length() > 0) { + padCp = properties.padString.char32At(0); + } else { + padCp = kFallbackPadChar; + } + return {padCp, properties.formatWidth, properties.padPosition.getOrDefault(UNUM_PAD_BEFORE_PREFIX)}; +} + int32_t Padder::padAndApply(const Modifier &mod1, const Modifier &mod2, NumberStringBuilder &string, int32_t leftIndex, int32_t rightIndex, UErrorCode &status) const { diff --git a/icu4c/source/i18n/number_patternstring.cpp b/icu4c/source/i18n/number_patternstring.cpp index 7bdd6fb71dd..7ec0297c6ec 100644 --- a/icu4c/source/i18n/number_patternstring.cpp +++ b/icu4c/source/i18n/number_patternstring.cpp @@ -32,6 +32,11 @@ PatternParser::parseToProperties(const UnicodeString& pattern, IgnoreRounding ig return properties; } +DecimalFormatProperties PatternParser::parseToProperties(const UnicodeString& pattern, + UErrorCode& status) { + return parseToProperties(pattern, IGNORE_ROUNDING_NEVER, status); +} + void PatternParser::parseToExistingProperties(const UnicodeString& pattern, DecimalFormatProperties& properties, IgnoreRounding ignoreRounding, UErrorCode& status) { diff --git a/icu4c/source/i18n/number_patternstring.h b/icu4c/source/i18n/number_patternstring.h index d0e62ef21f4..742ee3547cd 100644 --- a/icu4c/source/i18n/number_patternstring.h +++ b/icu4c/source/i18n/number_patternstring.h @@ -177,6 +177,8 @@ class U_I18N_API PatternParser { static DecimalFormatProperties parseToProperties(const UnicodeString& pattern, IgnoreRounding ignoreRounding, UErrorCode& status); + static DecimalFormatProperties parseToProperties(const UnicodeString& pattern, UErrorCode& status); + /** * Parses a pattern string into an existing property bag. All properties that can be encoded into a pattern string * will be overwritten with either their default value or with the value coming from the pattern string. Properties diff --git a/icu4c/source/i18n/number_types.h b/icu4c/source/i18n/number_types.h index 35a94bcdedf..ac0188f4982 100644 --- a/icu4c/source/i18n/number_types.h +++ b/icu4c/source/i18n/number_types.h @@ -305,6 +305,10 @@ class U_I18N_API NullableValue { return fValue; } + T getOrDefault(T defaultValue) const { + return fNull ? defaultValue : fValue; + } + private: bool fNull; T fValue; diff --git a/icu4c/source/i18n/unicode/compactdecimalformat.h b/icu4c/source/i18n/unicode/compactdecimalformat.h index f5911176c8d..e5d27de05a6 100644 --- a/icu4c/source/i18n/unicode/compactdecimalformat.h +++ b/icu4c/source/i18n/unicode/compactdecimalformat.h @@ -112,7 +112,7 @@ public: * other classes have different class IDs. * @stable ICU 51 */ - virtual UClassID getDynamicClassID() const; + virtual UClassID getDynamicClassID() const U_OVERRIDE; }; U_NAMESPACE_END diff --git a/icu4c/source/i18n/unicode/decimfmt.h b/icu4c/source/i18n/unicode/decimfmt.h index 443aa1a532e..88d50c7a891 100644 --- a/icu4c/source/i18n/unicode/decimfmt.h +++ b/icu4c/source/i18n/unicode/decimfmt.h @@ -42,7 +42,6 @@ #include "unicode/stringpiece.h" #include "unicode/curramt.h" #include "unicode/enumset.h" -#include "unicode/numberformatter.h" #ifndef U_HIDE_INTERNAL_API /** @@ -68,9 +67,11 @@ class PluralRules; class VisibleDigitsWithExponent; namespace number { +class LocalizedNumberFormatter; namespace impl { class DecimalQuantity; struct DecimalFormatProperties; +struct DecimalFormatWarehouse; } } @@ -1948,7 +1949,7 @@ class U_I18N_API DecimalFormat : public NumberFormat { * @return An instance of LocalizedNumberFormatter with the same behavior as this DecimalFormat. * @draft ICU 62 */ - number::LocalizedNumberFormatter toNumberFormatter() const; + const number::LocalizedNumberFormatter& toNumberFormatter() const; /** * Return the class ID for this class. This is useful only for @@ -2023,6 +2024,9 @@ class U_I18N_API DecimalFormat : public NumberFormat { */ LocalPointer fExportedProperties; + /** A field for a few additional helper object that need ownership. */ + LocalPointer fWarehouse; + LocalPointer fParser; LocalPointer fParserWithCurrency; diff --git a/icu4j/main/classes/core/src/com/ibm/icu/impl/number/Padder.java b/icu4j/main/classes/core/src/com/ibm/icu/impl/number/Padder.java index efb4cec0951..97a310900da 100644 --- a/icu4j/main/classes/core/src/com/ibm/icu/impl/number/Padder.java +++ b/icu4j/main/classes/core/src/com/ibm/icu/impl/number/Padder.java @@ -66,6 +66,12 @@ public class Padder { } } + public static Padder forProperties(DecimalFormatProperties properties) { + return new Padder(properties.getPadString(), + properties.getFormatWidth(), + properties.getPadPosition()); + } + public boolean isValid() { return targetWidth > 0; } diff --git a/icu4j/main/classes/core/src/com/ibm/icu/number/NumberPropertyMapper.java b/icu4j/main/classes/core/src/com/ibm/icu/number/NumberPropertyMapper.java index 168b43989ce..0d33059eda4 100644 --- a/icu4j/main/classes/core/src/com/ibm/icu/number/NumberPropertyMapper.java +++ b/icu4j/main/classes/core/src/com/ibm/icu/number/NumberPropertyMapper.java @@ -54,6 +54,8 @@ final class NumberPropertyMapper { /** * Convenience method to create a NumberFormatter directly from a pattern string. Something like this * could become public API if there is demand. + * + * NOTE: This appears to be dead code. */ public static UnlocalizedNumberFormatter create(String pattern, DecimalFormatSymbols symbols) { DecimalFormatProperties properties = PatternStringParser.parseToProperties(pattern); @@ -159,13 +161,13 @@ final class NumberPropertyMapper { if (minInt == 0 && maxFrac != 0) { // Force a digit after the decimal point. minFrac = minFrac <= 0 ? 1 : minFrac; - maxFrac = maxFrac < 0 ? Integer.MAX_VALUE : maxFrac < minFrac ? minFrac : maxFrac; + maxFrac = maxFrac < 0 ? -1 : maxFrac < minFrac ? minFrac : maxFrac; minInt = 0; maxInt = maxInt < 0 ? -1 : maxInt > RoundingUtils.MAX_INT_FRAC_SIG ? -1 : maxInt; } else { // Force a digit before the decimal point. minFrac = minFrac < 0 ? 0 : minFrac; - maxFrac = maxFrac < 0 ? Integer.MAX_VALUE : maxFrac < minFrac ? minFrac : maxFrac; + maxFrac = maxFrac < 0 ? -1 : maxFrac < minFrac ? minFrac : maxFrac; minInt = minInt <= 0 ? 1 : minInt > RoundingUtils.MAX_INT_FRAC_SIG ? 1 : minInt; maxInt = maxInt < 0 ? -1 : maxInt < minInt ? minInt : maxInt > RoundingUtils.MAX_INT_FRAC_SIG ? -1 : maxInt; @@ -210,9 +212,7 @@ final class NumberPropertyMapper { ///////////// if (properties.getFormatWidth() != -1) { - macros.padder = new Padder(properties.getPadString(), - properties.getFormatWidth(), - properties.getPadPosition()); + macros.padder = Padder.forProperties(properties); } /////////////////////////////// -- 2.40.0