(&other);
+ if (_other == nullptr) {
+ return false;
+ }
+ // TODO: Change this to use LocalizedNumberFormatter::operator== if it is ever proposed.
+ // This implementation is fine, but not particularly efficient.
+ UErrorCode localStatus = U_ZERO_ERROR;
+ return fFormatter.toSkeleton(localStatus) == _other->fFormatter.toSkeleton(localStatus);
+}
+
+Format* LocalizedNumberFormatterAsFormat::clone() const {
+ return new LocalizedNumberFormatterAsFormat(*this);
+}
+
+UnicodeString& LocalizedNumberFormatterAsFormat::format(const Formattable& obj, UnicodeString& appendTo,
+ FieldPosition& pos, UErrorCode& status) const {
+ if (U_FAILURE(status)) { return appendTo; }
+ UFormattedNumberData data;
+ obj.populateDecimalQuantity(data.quantity, status);
+ if (U_FAILURE(status)) {
+ return appendTo;
+ }
+ fFormatter.formatImpl(&data, status);
+ if (U_FAILURE(status)) {
+ return appendTo;
+ }
+ // always return first occurrence:
+ pos.setBeginIndex(0);
+ pos.setEndIndex(0);
+ bool found = data.string.nextFieldPosition(pos, status);
+ if (found && appendTo.length() != 0) {
+ pos.setBeginIndex(pos.getBeginIndex() + appendTo.length());
+ pos.setEndIndex(pos.getEndIndex() + appendTo.length());
+ }
+ appendTo.append(data.string.toTempUnicodeString());
+ return appendTo;
+}
+
+UnicodeString& LocalizedNumberFormatterAsFormat::format(const Formattable& obj, UnicodeString& appendTo,
+ FieldPositionIterator* posIter,
+ UErrorCode& status) const {
+ if (U_FAILURE(status)) { return appendTo; }
+ UFormattedNumberData data;
+ obj.populateDecimalQuantity(data.quantity, status);
+ if (U_FAILURE(status)) {
+ return appendTo;
+ }
+ fFormatter.formatImpl(&data, status);
+ if (U_FAILURE(status)) {
+ return appendTo;
+ }
+ appendTo.append(data.string.toTempUnicodeString());
+ if (posIter != nullptr) {
+ FieldPositionIteratorHandler fpih(posIter, status);
+ data.string.getAllFieldPositions(fpih, status);
+ }
+ return appendTo;
+}
+
+void LocalizedNumberFormatterAsFormat::parseObject(const UnicodeString&, Formattable&,
+ ParsePosition& parse_pos) const {
+ // Not supported.
+ parse_pos.setErrorIndex(0);
+}
+
+const LocalizedNumberFormatter& LocalizedNumberFormatterAsFormat::getNumberFormatter() const {
+ return fFormatter;
+}
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/icu4c/source/i18n/number_asformat.h b/icu4c/source/i18n/number_asformat.h
new file mode 100644
index 00000000000..0ceb0c1479e
--- /dev/null
+++ b/icu4c/source/i18n/number_asformat.h
@@ -0,0 +1,104 @@
+// © 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
+#ifndef __NUMBER_ASFORMAT_H__
+#define __NUMBER_ASFORMAT_H__
+
+#include "unicode/numberformatter.h"
+#include "number_types.h"
+#include "number_decimalquantity.h"
+#include "number_scientific.h"
+#include "number_patternstring.h"
+#include "number_modifiers.h"
+#include "number_multiplier.h"
+#include "number_roundingutils.h"
+#include "decNumber.h"
+#include "charstr.h"
+
+U_NAMESPACE_BEGIN namespace number {
+namespace impl {
+
+/**
+ * A wrapper around LocalizedNumberFormatter implementing the Format interface, enabling improved
+ * compatibility with other APIs.
+ *
+ * @draft ICU 62
+ * @see NumberFormatter
+ */
+class U_I18N_API LocalizedNumberFormatterAsFormat : public Format {
+ public:
+ LocalizedNumberFormatterAsFormat(const LocalizedNumberFormatter& formatter, const Locale& locale);
+
+ /**
+ * Destructor.
+ */
+ ~LocalizedNumberFormatterAsFormat() U_OVERRIDE;
+
+ /**
+ * Equals operator.
+ */
+ UBool operator==(const Format& other) const U_OVERRIDE;
+
+ /**
+ * Creates a copy of this object.
+ */
+ Format* clone() const U_OVERRIDE;
+
+ /**
+ * Formats a Number using the wrapped LocalizedNumberFormatter. The provided formattable must be a
+ * number type.
+ */
+ UnicodeString& format(const Formattable& obj, UnicodeString& appendTo, FieldPosition& pos,
+ UErrorCode& status) const U_OVERRIDE;
+
+ /**
+ * Formats a Number using the wrapped LocalizedNumberFormatter. The provided formattable must be a
+ * number type.
+ */
+ UnicodeString& format(const Formattable& obj, UnicodeString& appendTo, FieldPositionIterator* posIter,
+ UErrorCode& status) const U_OVERRIDE;
+
+ /**
+ * Not supported: sets an error index and returns.
+ */
+ void parseObject(const UnicodeString& source, Formattable& result,
+ ParsePosition& parse_pos) const U_OVERRIDE;
+
+ /**
+ * Gets the LocalizedNumberFormatter that this wrapper class uses to format numbers.
+ *
+ * For maximum efficiency, this function returns by const reference. You must copy the return value
+ * into a local variable if you want to use it beyond the lifetime of the current object:
+ *
+ *
+ * LocalizedNumberFormatter localFormatter = fmt->getNumberFormatter();
+ *
+ *
+ * You can however use the return value directly when chaining:
+ *
+ *
+ * FormattedNumber result = fmt->getNumberFormatter().formatDouble(514.23, status);
+ *
+ *
+ * @return The unwrapped LocalizedNumberFormatter.
+ */
+ const LocalizedNumberFormatter& getNumberFormatter() const;
+
+ private:
+ LocalizedNumberFormatter fFormatter;
+
+ // Even though the locale is inside the LocalizedNumberFormatter, we have to keep it here, too, because
+ // LocalizedNumberFormatter doesn't have a getLocale() method, and ICU-TC didn't want to add one.
+ Locale fLocale;
+};
+
+} // namespace impl
+} // namespace number
+U_NAMESPACE_END
+
+#endif // __NUMBER_ASFORMAT_H__
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/icu4c/source/i18n/number_compact.cpp b/icu4c/source/i18n/number_compact.cpp
index 7cadba688a1..40278e1a012 100644
--- a/icu4c/source/i18n/number_compact.cpp
+++ b/icu4c/source/i18n/number_compact.cpp
@@ -5,12 +5,13 @@
#if !UCONFIG_NO_FORMATTING
-#include "resource.h"
-#include "number_compact.h"
#include "unicode/ustring.h"
#include "unicode/ures.h"
#include "cstring.h"
#include "charstr.h"
+#include "resource.h"
+#include "number_compact.h"
+#include "number_microprops.h"
#include "uresimp.h"
using namespace icu;
@@ -283,7 +284,7 @@ void CompactHandler::processQuantity(DecimalQuantity &quantity, MicroProps &micr
magnitude -= multiplier;
}
- StandardPlural::Form plural = quantity.getStandardPlural(rules);
+ StandardPlural::Form plural = utils::getStandardPlural(rules, quantity);
const UChar *patternString = data.getPattern(magnitude, plural);
if (patternString == nullptr) {
// Use the default (non-compact) modifier.
diff --git a/icu4c/source/i18n/number_decimalquantity.cpp b/icu4c/source/i18n/number_decimalquantity.cpp
index 24b5263fdab..88304190dbb 100644
--- a/icu4c/source/i18n/number_decimalquantity.cpp
+++ b/icu4c/source/i18n/number_decimalquantity.cpp
@@ -12,6 +12,7 @@
#include "unicode/plurrule.h"
#include "cmemory.h"
+#include "number_decnum.h"
#include "putilimp.h"
#include "number_decimalquantity.h"
#include "number_roundingutils.h"
@@ -68,6 +69,7 @@ static double DOUBLE_MULTIPLIERS[] = {
} // namespace
+icu::IFixedDecimal::~IFixedDecimal() = default;
DecimalQuantity::DecimalQuantity() {
setBcdToZero();
@@ -236,16 +238,6 @@ bool DecimalQuantity::adjustMagnitude(int32_t delta) {
return false;
}
-StandardPlural::Form DecimalQuantity::getStandardPlural(const PluralRules *rules) const {
- if (rules == nullptr) {
- // Fail gracefully if the user didn't provide a PluralRules
- return StandardPlural::Form::OTHER;
- } else {
- UnicodeString ruleString = rules->select(*this);
- return StandardPlural::orOtherFromString(ruleString);
- }
-}
-
double DecimalQuantity::getPluralOperand(PluralOperand operand) const {
// If this assertion fails, you need to call roundToInfinity() or some other rounding method.
// See the comment at the top of this file explaining the "isApproximate" field.
diff --git a/icu4c/source/i18n/number_decimalquantity.h b/icu4c/source/i18n/number_decimalquantity.h
index 7619ce2e4d1..8e04dea7eb5 100644
--- a/icu4c/source/i18n/number_decimalquantity.h
+++ b/icu4c/source/i18n/number_decimalquantity.h
@@ -194,15 +194,6 @@ class U_I18N_API DecimalQuantity : public IFixedDecimal, public UMemory {
*/
void appendDigit(int8_t value, int32_t leadingZeros, bool appendAsInteger);
- /**
- * Computes the plural form for this number based on the specified set of rules.
- *
- * @param rules A {@link PluralRules} object representing the set of rules.
- * @return The {@link StandardPlural} according to the PluralRules. If the plural form is not in
- * the set of standard plurals, {@link StandardPlural#OTHER} is returned instead.
- */
- StandardPlural::Form getStandardPlural(const PluralRules *rules) const;
-
double getPluralOperand(PluralOperand operand) const U_OVERRIDE;
bool hasIntegerValue() const U_OVERRIDE;
diff --git a/icu4c/source/i18n/number_decnum.h b/icu4c/source/i18n/number_decnum.h
new file mode 100644
index 00000000000..a7793470b55
--- /dev/null
+++ b/icu4c/source/i18n/number_decnum.h
@@ -0,0 +1,77 @@
+// © 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
+#ifndef __NUMBER_DECNUM_H__
+#define __NUMBER_DECNUM_H__
+
+#include "decNumber.h"
+#include "charstr.h"
+
+U_NAMESPACE_BEGIN
+
+#define DECNUM_INITIAL_CAPACITY 34
+
+// Export an explicit template instantiation of the MaybeStackHeaderAndArray that is used as a data member of DecNum.
+// When building DLLs for Windows this is required even though no direct access to the MaybeStackHeaderAndArray leaks out of the i18n library.
+// (See digitlst.h, pluralaffix.h, datefmt.h, and others for similar examples.)
+#if U_PF_WINDOWS <= U_PLATFORM && U_PLATFORM <= U_PF_CYGWIN
+template class U_I18N_API MaybeStackHeaderAndArray;
+#endif
+
+namespace number {
+namespace impl {
+
+/** A very thin C++ wrapper around decNumber.h */
+// Exported as U_I18N_API for tests
+class U_I18N_API DecNum : public UMemory {
+ public:
+ DecNum(); // leaves object in valid but undefined state
+
+ // Copy-like constructor; use the default move operators.
+ DecNum(const DecNum& other, UErrorCode& status);
+
+ /** Sets the decNumber to the StringPiece. */
+ void setTo(StringPiece str, UErrorCode& status);
+
+ /** Sets the decNumber to the NUL-terminated char string. */
+ void setTo(const char* str, UErrorCode& status);
+
+ /** Uses double_conversion to set this decNumber to the given double. */
+ void setTo(double d, UErrorCode& status);
+
+ /** Sets the decNumber to the BCD representation. */
+ void setTo(const uint8_t* bcd, int32_t length, int32_t scale, bool isNegative, UErrorCode& status);
+
+ void normalize();
+
+ void multiplyBy(const DecNum& rhs, UErrorCode& status);
+
+ void divideBy(const DecNum& rhs, UErrorCode& status);
+
+ bool isNegative() const;
+
+ bool isZero() const;
+
+ inline const decNumber* getRawDecNumber() const {
+ return fData.getAlias();
+ }
+
+ private:
+ static constexpr int32_t kDefaultDigits = DECNUM_INITIAL_CAPACITY;
+ MaybeStackHeaderAndArray fData;
+ decContext fContext;
+
+ void _setTo(const char* str, int32_t maxDigits, UErrorCode& status);
+};
+
+} // namespace impl
+} // namespace number
+
+U_NAMESPACE_END
+
+#endif // __NUMBER_DECNUM_H__
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/icu4c/source/i18n/number_fluent.cpp b/icu4c/source/i18n/number_fluent.cpp
index 67ada4460fd..687adb6b5ba 100644
--- a/icu4c/source/i18n/number_fluent.cpp
+++ b/icu4c/source/i18n/number_fluent.cpp
@@ -10,6 +10,7 @@
#include "number_decimalquantity.h"
#include "number_formatimpl.h"
#include "umutex.h"
+#include "number_asformat.h"
#include "number_skeletons.h"
#include "number_utils.h"
#include "number_utypes.h"
diff --git a/icu4c/source/i18n/number_formatimpl.h b/icu4c/source/i18n/number_formatimpl.h
index f425bbca48a..744fecec13f 100644
--- a/icu4c/source/i18n/number_formatimpl.h
+++ b/icu4c/source/i18n/number_formatimpl.h
@@ -14,6 +14,7 @@
#include "number_patternmodifier.h"
#include "number_longnames.h"
#include "number_compact.h"
+#include "number_microprops.h"
U_NAMESPACE_BEGIN namespace number {
namespace impl {
diff --git a/icu4c/source/i18n/number_longnames.cpp b/icu4c/source/i18n/number_longnames.cpp
index cc0dd78d6d2..26f9af4c9bd 100644
--- a/icu4c/source/i18n/number_longnames.cpp
+++ b/icu4c/source/i18n/number_longnames.cpp
@@ -11,6 +11,7 @@
#include "charstr.h"
#include "uresimp.h"
#include "number_longnames.h"
+#include "number_microprops.h"
#include
#include "cstring.h"
@@ -261,7 +262,7 @@ void LongNameHandler::processQuantity(DecimalQuantity &quantity, MicroProps &mic
// TODO: Avoid the copy here?
DecimalQuantity copy(quantity);
micros.rounder.apply(copy, status);
- micros.modOuter = &fModifiers[copy.getStandardPlural(rules)];
+ micros.modOuter = &fModifiers[utils::getStandardPlural(rules, copy)];
}
#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/icu4c/source/i18n/number_microprops.h b/icu4c/source/i18n/number_microprops.h
new file mode 100644
index 00000000000..daa887bb0dd
--- /dev/null
+++ b/icu4c/source/i18n/number_microprops.h
@@ -0,0 +1,82 @@
+// © 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
+#ifndef __NUMBER_MICROPROPS_H__
+#define __NUMBER_MICROPROPS_H__
+
+// TODO: minimize includes
+#include "unicode/numberformatter.h"
+#include "number_types.h"
+#include "number_decimalquantity.h"
+#include "number_scientific.h"
+#include "number_patternstring.h"
+#include "number_modifiers.h"
+#include "number_multiplier.h"
+#include "number_roundingutils.h"
+#include "decNumber.h"
+#include "charstr.h"
+
+U_NAMESPACE_BEGIN namespace number {
+namespace impl {
+
+struct MicroProps : public MicroPropsGenerator {
+
+ // NOTE: All of these fields are properly initialized in NumberFormatterImpl.
+ RoundingImpl rounder;
+ Grouper grouping;
+ Padder padding;
+ IntegerWidth integerWidth;
+ UNumberSignDisplay sign;
+ UNumberDecimalSeparatorDisplay decimal;
+ bool useCurrency;
+
+ // Note: This struct has no direct ownership of the following pointers.
+ const DecimalFormatSymbols* symbols;
+ const Modifier* modOuter;
+ const Modifier* modMiddle;
+ const Modifier* modInner;
+
+ // The following "helper" fields may optionally be used during the MicroPropsGenerator.
+ // They live here to retain memory.
+ struct {
+ ScientificModifier scientificModifier;
+ EmptyModifier emptyWeakModifier{false};
+ EmptyModifier emptyStrongModifier{true};
+ MultiplierFormatHandler multiplier;
+ } helpers;
+
+
+ MicroProps() = default;
+
+ MicroProps(const MicroProps& other) = default;
+
+ MicroProps& operator=(const MicroProps& other) = default;
+
+ void processQuantity(DecimalQuantity&, MicroProps& micros, UErrorCode& status) const U_OVERRIDE {
+ (void) status;
+ if (this == µs) {
+ // Unsafe path: no need to perform a copy.
+ U_ASSERT(!exhausted);
+ micros.exhausted = true;
+ U_ASSERT(exhausted);
+ } else {
+ // Safe path: copy self into the output micros.
+ micros = *this;
+ }
+ }
+
+ private:
+ // Internal fields:
+ bool exhausted = false;
+};
+
+} // namespace impl
+} // namespace number
+U_NAMESPACE_END
+
+#endif // __NUMBER_MICROPROPS_H__
+
+#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/icu4c/source/i18n/number_multiplier.cpp b/icu4c/source/i18n/number_multiplier.cpp
index 1faeac41d7b..a27142c9bd6 100644
--- a/icu4c/source/i18n/number_multiplier.cpp
+++ b/icu4c/source/i18n/number_multiplier.cpp
@@ -9,6 +9,7 @@
// Helpful in toString methods and elsewhere.
#define UNISTR_FROM_STRING_EXPLICIT
+#include "number_decnum.h"
#include "number_types.h"
#include "number_multiplier.h"
#include "numparse_validators.h"
@@ -152,21 +153,4 @@ void MultiplierFormatHandler::processQuantity(DecimalQuantity& quantity, MicroPr
multiplier.applyTo(quantity);
}
-
-// NOTE: MultiplierParseHandler is declared in the header numparse_validators.h
-MultiplierParseHandler::MultiplierParseHandler(::icu::number::Scale multiplier)
- : fMultiplier(std::move(multiplier)) {}
-
-void MultiplierParseHandler::postProcess(ParsedNumber& result) const {
- if (!result.quantity.bogus) {
- fMultiplier.applyReciprocalTo(result.quantity);
- // NOTE: It is okay if the multiplier was negative.
- }
-}
-
-UnicodeString MultiplierParseHandler::toString() const {
- return u"";
-}
-
-
#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/icu4c/source/i18n/number_patternmodifier.cpp b/icu4c/source/i18n/number_patternmodifier.cpp
index b45647d143d..6417e14378b 100644
--- a/icu4c/source/i18n/number_patternmodifier.cpp
+++ b/icu4c/source/i18n/number_patternmodifier.cpp
@@ -10,6 +10,7 @@
#include "unicode/dcfmtsym.h"
#include "unicode/ucurr.h"
#include "unicode/unistr.h"
+#include "number_microprops.h"
using namespace icu;
using namespace icu::number;
@@ -136,7 +137,7 @@ void ImmutablePatternModifier::applyToMicros(MicroProps& micros, DecimalQuantity
// TODO: Fix this. Avoid the copy.
DecimalQuantity copy(quantity);
copy.roundToInfinity();
- StandardPlural::Form plural = copy.getStandardPlural(rules);
+ StandardPlural::Form plural = utils::getStandardPlural(rules, copy);
micros.modMiddle = pm->getModifier(quantity.signum(), plural);
}
}
@@ -166,7 +167,7 @@ void MutablePatternModifier::processQuantity(DecimalQuantity& fq, MicroProps& mi
// TODO: Fix this. Avoid the copy.
DecimalQuantity copy(fq);
micros.rounder.apply(copy, status);
- nonConstThis->setNumberProperties(fq.signum(), copy.getStandardPlural(rules));
+ nonConstThis->setNumberProperties(fq.signum(), utils::getStandardPlural(rules, copy));
} else {
nonConstThis->setNumberProperties(fq.signum(), StandardPlural::Form::COUNT);
}
diff --git a/icu4c/source/i18n/number_scientific.cpp b/icu4c/source/i18n/number_scientific.cpp
index 72288f208a3..e9adfb402bd 100644
--- a/icu4c/source/i18n/number_scientific.cpp
+++ b/icu4c/source/i18n/number_scientific.cpp
@@ -10,6 +10,7 @@
#include "number_utils.h"
#include "number_stringbuilder.h"
#include "unicode/unum.h"
+#include "number_microprops.h"
using namespace icu;
using namespace icu::number;
diff --git a/icu4c/source/i18n/number_skeletons.cpp b/icu4c/source/i18n/number_skeletons.cpp
index bae38ac445e..db2aabcffb6 100644
--- a/icu4c/source/i18n/number_skeletons.cpp
+++ b/icu4c/source/i18n/number_skeletons.cpp
@@ -9,6 +9,7 @@
// Helpful in toString methods and elsewhere.
#define UNISTR_FROM_STRING_EXPLICIT
+#include "number_decnum.h"
#include "number_skeletons.h"
#include "umutex.h"
#include "ucln_in.h"
diff --git a/icu4c/source/i18n/number_utils.cpp b/icu4c/source/i18n/number_utils.cpp
index ab6d5fab72c..c79d2de9fa3 100644
--- a/icu4c/source/i18n/number_utils.cpp
+++ b/icu4c/source/i18n/number_utils.cpp
@@ -11,6 +11,7 @@
#include
#include
+#include "number_decnum.h"
#include "number_types.h"
#include "number_utils.h"
#include "charstr.h"
@@ -20,7 +21,6 @@
#include "fphdlimp.h"
#include "uresimp.h"
#include "ureslocs.h"
-#include "number_utypes.h"
using namespace icu;
using namespace icu::number;
@@ -49,86 +49,6 @@ doGetPattern(UResourceBundle* res, const char* nsName, const char* patternKey, U
}
-LocalizedNumberFormatterAsFormat::LocalizedNumberFormatterAsFormat(
- const LocalizedNumberFormatter& formatter, const Locale& locale)
- : fFormatter(formatter), fLocale(locale) {
- const char* localeName = locale.getName();
- setLocaleIDs(localeName, localeName);
-}
-
-LocalizedNumberFormatterAsFormat::~LocalizedNumberFormatterAsFormat() = default;
-
-UBool LocalizedNumberFormatterAsFormat::operator==(const Format& other) const {
- auto* _other = dynamic_cast(&other);
- if (_other == nullptr) {
- return false;
- }
- // TODO: Change this to use LocalizedNumberFormatter::operator== if it is ever proposed.
- // This implementation is fine, but not particularly efficient.
- UErrorCode localStatus = U_ZERO_ERROR;
- return fFormatter.toSkeleton(localStatus) == _other->fFormatter.toSkeleton(localStatus);
-}
-
-Format* LocalizedNumberFormatterAsFormat::clone() const {
- return new LocalizedNumberFormatterAsFormat(*this);
-}
-
-UnicodeString& LocalizedNumberFormatterAsFormat::format(const Formattable& obj, UnicodeString& appendTo,
- FieldPosition& pos, UErrorCode& status) const {
- if (U_FAILURE(status)) { return appendTo; }
- UFormattedNumberData data;
- obj.populateDecimalQuantity(data.quantity, status);
- if (U_FAILURE(status)) {
- return appendTo;
- }
- fFormatter.formatImpl(&data, status);
- if (U_FAILURE(status)) {
- return appendTo;
- }
- // always return first occurrence:
- pos.setBeginIndex(0);
- pos.setEndIndex(0);
- bool found = data.string.nextFieldPosition(pos, status);
- if (found && appendTo.length() != 0) {
- pos.setBeginIndex(pos.getBeginIndex() + appendTo.length());
- pos.setEndIndex(pos.getEndIndex() + appendTo.length());
- }
- appendTo.append(data.string.toTempUnicodeString());
- return appendTo;
-}
-
-UnicodeString& LocalizedNumberFormatterAsFormat::format(const Formattable& obj, UnicodeString& appendTo,
- FieldPositionIterator* posIter,
- UErrorCode& status) const {
- if (U_FAILURE(status)) { return appendTo; }
- UFormattedNumberData data;
- obj.populateDecimalQuantity(data.quantity, status);
- if (U_FAILURE(status)) {
- return appendTo;
- }
- fFormatter.formatImpl(&data, status);
- if (U_FAILURE(status)) {
- return appendTo;
- }
- appendTo.append(data.string.toTempUnicodeString());
- if (posIter != nullptr) {
- FieldPositionIteratorHandler fpih(posIter, status);
- data.string.getAllFieldPositions(fpih, status);
- }
- return appendTo;
-}
-
-void LocalizedNumberFormatterAsFormat::parseObject(const UnicodeString&, Formattable&,
- ParsePosition& parse_pos) const {
- // Not supported.
- parse_pos.setErrorIndex(0);
-}
-
-const LocalizedNumberFormatter& LocalizedNumberFormatterAsFormat::getNumberFormatter() const {
- return fFormatter;
-}
-
-
const char16_t* utils::getPatternForStyle(const Locale& locale, const char* nsName, CldrPatternStyle style,
UErrorCode& status) {
const char* patternKey;
@@ -330,6 +250,4 @@ bool DecNum::isZero() const {
return decNumberIsZero(fData.getAlias());
}
-
-
#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/icu4c/source/i18n/number_utils.h b/icu4c/source/i18n/number_utils.h
index e11da139422..c367166009c 100644
--- a/icu4c/source/i18n/number_utils.h
+++ b/icu4c/source/i18n/number_utils.h
@@ -20,145 +20,9 @@
U_NAMESPACE_BEGIN
-#define DECNUM_INITIAL_CAPACITY 34
-
-// Export an explicit template instantiation of the MaybeStackHeaderAndArray that is used as a data member of DecNum.
-// When building DLLs for Windows this is required even though no direct access to the MaybeStackHeaderAndArray leaks out of the i18n library.
-// (See digitlst.h, pluralaffix.h, datefmt.h, and others for similar examples.)
-#if U_PF_WINDOWS <= U_PLATFORM && U_PLATFORM <= U_PF_CYGWIN
-template class U_I18N_API MaybeStackHeaderAndArray;
-#endif
-
namespace number {
namespace impl {
-struct MicroProps : public MicroPropsGenerator {
-
- // NOTE: All of these fields are properly initialized in NumberFormatterImpl.
- RoundingImpl rounder;
- Grouper grouping;
- Padder padding;
- IntegerWidth integerWidth;
- UNumberSignDisplay sign;
- UNumberDecimalSeparatorDisplay decimal;
- bool useCurrency;
-
- // Note: This struct has no direct ownership of the following pointers.
- const DecimalFormatSymbols* symbols;
- const Modifier* modOuter;
- const Modifier* modMiddle;
- const Modifier* modInner;
-
- // The following "helper" fields may optionally be used during the MicroPropsGenerator.
- // They live here to retain memory.
- struct {
- ScientificModifier scientificModifier;
- EmptyModifier emptyWeakModifier{false};
- EmptyModifier emptyStrongModifier{true};
- MultiplierFormatHandler multiplier;
- } helpers;
-
-
- MicroProps() = default;
-
- MicroProps(const MicroProps& other) = default;
-
- MicroProps& operator=(const MicroProps& other) = default;
-
- void processQuantity(DecimalQuantity&, MicroProps& micros, UErrorCode& status) const U_OVERRIDE {
- (void) status;
- if (this == µs) {
- // Unsafe path: no need to perform a copy.
- U_ASSERT(!exhausted);
- micros.exhausted = true;
- U_ASSERT(exhausted);
- } else {
- // Safe path: copy self into the output micros.
- micros = *this;
- }
- }
-
- private:
- // Internal fields:
- bool exhausted = false;
-};
-
-
-/**
- * A wrapper around LocalizedNumberFormatter implementing the Format interface, enabling improved
- * compatibility with other APIs.
- *
- * @draft ICU 62
- * @see NumberFormatter
- */
-class U_I18N_API LocalizedNumberFormatterAsFormat : public Format {
- public:
- LocalizedNumberFormatterAsFormat(const LocalizedNumberFormatter& formatter, const Locale& locale);
-
- /**
- * Destructor.
- */
- ~LocalizedNumberFormatterAsFormat() U_OVERRIDE;
-
- /**
- * Equals operator.
- */
- UBool operator==(const Format& other) const U_OVERRIDE;
-
- /**
- * Creates a copy of this object.
- */
- Format* clone() const U_OVERRIDE;
-
- /**
- * Formats a Number using the wrapped LocalizedNumberFormatter. The provided formattable must be a
- * number type.
- */
- UnicodeString& format(const Formattable& obj, UnicodeString& appendTo, FieldPosition& pos,
- UErrorCode& status) const U_OVERRIDE;
-
- /**
- * Formats a Number using the wrapped LocalizedNumberFormatter. The provided formattable must be a
- * number type.
- */
- UnicodeString& format(const Formattable& obj, UnicodeString& appendTo, FieldPositionIterator* posIter,
- UErrorCode& status) const U_OVERRIDE;
-
- /**
- * Not supported: sets an error index and returns.
- */
- void parseObject(const UnicodeString& source, Formattable& result,
- ParsePosition& parse_pos) const U_OVERRIDE;
-
- /**
- * Gets the LocalizedNumberFormatter that this wrapper class uses to format numbers.
- *
- * For maximum efficiency, this function returns by const reference. You must copy the return value
- * into a local variable if you want to use it beyond the lifetime of the current object:
- *
- *
- * LocalizedNumberFormatter localFormatter = fmt->getNumberFormatter();
- *
- *
- * You can however use the return value directly when chaining:
- *
- *
- * FormattedNumber result = fmt->getNumberFormatter().formatDouble(514.23, status);
- *
- *
- * @return The unwrapped LocalizedNumberFormatter.
- */
- const LocalizedNumberFormatter& getNumberFormatter() const;
-
- private:
- LocalizedNumberFormatter fFormatter;
-
- // Even though the locale is inside the LocalizedNumberFormatter, we have to keep it here, too, because
- // LocalizedNumberFormatter doesn't have a getLocale() method, and ICU-TC didn't want to add one.
- Locale fLocale;
-};
-
-
enum CldrPatternStyle {
CLDR_PATTERN_STYLE_DECIMAL,
CLDR_PATTERN_STYLE_CURRENCY,
@@ -200,55 +64,29 @@ inline bool unitIsPermille(const MeasureUnit& unit) {
const char16_t*
getPatternForStyle(const Locale& locale, const char* nsName, CldrPatternStyle style, UErrorCode& status);
-} // namespace utils
-
-
-/** A very thin C++ wrapper around decNumber.h */
-// Exported as U_I18N_API for tests
-class U_I18N_API DecNum : public UMemory {
- public:
- DecNum(); // leaves object in valid but undefined state
-
- // Copy-like constructor; use the default move operators.
- DecNum(const DecNum& other, UErrorCode& status);
-
- /** Sets the decNumber to the StringPiece. */
- void setTo(StringPiece str, UErrorCode& status);
-
- /** Sets the decNumber to the NUL-terminated char string. */
- void setTo(const char* str, UErrorCode& status);
-
- /** Uses double_conversion to set this decNumber to the given double. */
- void setTo(double d, UErrorCode& status);
-
- /** Sets the decNumber to the BCD representation. */
- void setTo(const uint8_t* bcd, int32_t length, int32_t scale, bool isNegative, UErrorCode& status);
-
- void normalize();
-
- void multiplyBy(const DecNum& rhs, UErrorCode& status);
-
- void divideBy(const DecNum& rhs, UErrorCode& status);
-
- bool isNegative() const;
-
- bool isZero() const;
-
- inline const decNumber* getRawDecNumber() const {
- return fData.getAlias();
+/**
+ * Computes the plural form for this number based on the specified set of rules.
+ *
+ * @param rules A {@link PluralRules} object representing the set of rules.
+ * @return The {@link StandardPlural} according to the PluralRules. If the plural form is not in
+ * the set of standard plurals, {@link StandardPlural#OTHER} is returned instead.
+ */
+inline StandardPlural::Form getStandardPlural(const PluralRules *rules,
+ const IFixedDecimal &fdec) {
+ if (rules == nullptr) {
+ // Fail gracefully if the user didn't provide a PluralRules
+ return StandardPlural::Form::OTHER;
+ } else {
+ UnicodeString ruleString = rules->select(fdec);
+ return StandardPlural::orOtherFromString(ruleString);
}
+}
- private:
- static constexpr int32_t kDefaultDigits = DECNUM_INITIAL_CAPACITY;
- MaybeStackHeaderAndArray fData;
- decContext fContext;
-
- void _setTo(const char* str, int32_t maxDigits, UErrorCode& status);
-};
-
+} // namespace utils
} // namespace impl
} // namespace number
+
U_NAMESPACE_END
#endif //__NUMBER_UTILS_H__
diff --git a/icu4c/source/i18n/numparse_validators.cpp b/icu4c/source/i18n/numparse_validators.cpp
index 62622ae976b..12d3465c4ef 100644
--- a/icu4c/source/i18n/numparse_validators.cpp
+++ b/icu4c/source/i18n/numparse_validators.cpp
@@ -68,5 +68,18 @@ UnicodeString RequireNumberValidator::toString() const {
return u"";
}
+MultiplierParseHandler::MultiplierParseHandler(::icu::number::Scale multiplier)
+ : fMultiplier(std::move(multiplier)) {}
+
+void MultiplierParseHandler::postProcess(ParsedNumber& result) const {
+ if (!result.quantity.bogus) {
+ fMultiplier.applyReciprocalTo(result.quantity);
+ // NOTE: It is okay if the multiplier was negative.
+ }
+}
+
+UnicodeString MultiplierParseHandler::toString() const {
+ return u"";
+}
#endif /* #if !UCONFIG_NO_FORMATTING */
diff --git a/icu4c/source/i18n/numparse_validators.h b/icu4c/source/i18n/numparse_validators.h
index f6768938c1e..5d43b779d0b 100644
--- a/icu4c/source/i18n/numparse_validators.h
+++ b/icu4c/source/i18n/numparse_validators.h
@@ -71,8 +71,6 @@ class RequireNumberValidator : public ValidationMatcher, public UMemory {
/**
* Wraps a {@link Multiplier} for use in the number parsing pipeline.
- *
- * NOTE: Implemented in number_multiplier.cpp
*/
class MultiplierParseHandler : public ValidationMatcher, public UMemory {
public:
diff --git a/icu4c/source/i18n/plurrule.cpp b/icu4c/source/i18n/plurrule.cpp
index 04e4d825f6a..aedb924c618 100644
--- a/icu4c/source/i18n/plurrule.cpp
+++ b/icu4c/source/i18n/plurrule.cpp
@@ -248,26 +248,6 @@ PluralRules::select(double number) const {
return select(FixedDecimal(number));
}
-UnicodeString
-PluralRules::select(const Formattable& obj, const NumberFormat& fmt, UErrorCode& status) const {
- if (U_SUCCESS(status)) {
- const DecimalFormat *decFmt = dynamic_cast(&fmt);
- if (decFmt != NULL) {
- number::impl::DecimalQuantity dq;
- decFmt->formatToDecimalQuantity(obj, dq, status);
- if (U_SUCCESS(status)) {
- return select(dq);
- }
- } else {
- double number = obj.getDouble(status);
- if (U_SUCCESS(status)) {
- return select(number);
- }
- }
- }
- return UnicodeString();
-}
-
UnicodeString
PluralRules::select(const IFixedDecimal &number) const {
if (mRules == NULL) {
@@ -1418,8 +1398,6 @@ PluralOperand tokenTypeToPluralOperand(tokenType tt) {
}
}
-IFixedDecimal::~IFixedDecimal() = default;
-
FixedDecimal::FixedDecimal(double n, int32_t v, int64_t f) {
init(n, v, f);
// check values. TODO make into unit test.
diff --git a/icu4c/source/i18n/unicode/plurrule.h b/icu4c/source/i18n/unicode/plurrule.h
index 7a1ad1d1a12..03dea3f1b92 100644
--- a/icu4c/source/i18n/unicode/plurrule.h
+++ b/icu4c/source/i18n/unicode/plurrule.h
@@ -347,22 +347,6 @@ public:
UnicodeString select(double number) const;
#ifndef U_HIDE_INTERNAL_API
- /**
- * Given a number and a format, returns the keyword of the first applicable
- * rule for this PluralRules object.
- * Note: This internal preview interface may be removed in the future if
- * an architecturally cleaner solution reaches stable status.
- * @param obj The numeric object for which the rule should be determined.
- * @param fmt The NumberFormat specifying how the number will be formatted
- * (this can affect the plural form, e.g. "1 dollar" vs "1.0 dollars").
- * @param status Input/output parameter. If at entry this indicates a
- * failure status, the method returns immediately; otherwise
- * this is set to indicate the outcome of the call.
- * @return The keyword of the selected rule. Undefined in the case of an error.
- * @internal ICU 59 technology preview, may be removed in the future
- */
- UnicodeString select(const Formattable& obj, const NumberFormat& fmt, UErrorCode& status) const;
-
/**
* @internal
*/
diff --git a/icu4c/source/i18n/upluralrules.cpp b/icu4c/source/i18n/upluralrules.cpp
index 24e74e3ee22..bba6dfe3101 100644
--- a/icu4c/source/i18n/upluralrules.cpp
+++ b/icu4c/source/i18n/upluralrules.cpp
@@ -17,9 +17,44 @@
#include "unicode/unistr.h"
#include "unicode/unum.h"
#include "unicode/numfmt.h"
+#include "number_decimalquantity.h"
U_NAMESPACE_USE
+namespace {
+
+/**
+ * Given a number and a format, returns the keyword of the first applicable
+ * rule for the PluralRules object.
+ * @param rules The plural rules.
+ * @param obj The numeric object for which the rule should be determined.
+ * @param fmt The NumberFormat specifying how the number will be formatted
+ * (this can affect the plural form, e.g. "1 dollar" vs "1.0 dollars").
+ * @param status Input/output parameter. If at entry this indicates a
+ * failure status, the method returns immediately; otherwise
+ * this is set to indicate the outcome of the call.
+ * @return The keyword of the selected rule. Undefined in the case of an error.
+ */
+UnicodeString select(const PluralRules &rules, const Formattable& obj, const NumberFormat& fmt, UErrorCode& status) {
+ if (U_SUCCESS(status)) {
+ const DecimalFormat *decFmt = dynamic_cast(&fmt);
+ if (decFmt != NULL) {
+ number::impl::DecimalQuantity dq;
+ decFmt->formatToDecimalQuantity(obj, dq, status);
+ if (U_SUCCESS(status)) {
+ return rules.select(dq);
+ }
+ } else {
+ double number = obj.getDouble(status);
+ if (U_SUCCESS(status)) {
+ return rules.select(number);
+ }
+ }
+ }
+ return UnicodeString();
+}
+
+} // namespace
U_CAPI UPluralRules* U_EXPORT2
uplrules_open(const char *locale, UErrorCode *status)
@@ -73,7 +108,7 @@ uplrules_selectWithFormat(const UPluralRules *uplrules,
return 0;
}
Formattable obj(number);
- UnicodeString result = plrules->select(obj, *nf, *status);
+ UnicodeString result = select(*plrules, obj, *nf, *status);
return result.extract(keyword, capacity, *status);
}
diff --git a/icu4c/source/test/depstest/dependencies.txt b/icu4c/source/test/depstest/dependencies.txt
index f4605547dc7..55783ee04ed 100644
--- a/icu4c/source/test/depstest/dependencies.txt
+++ b/icu4c/source/test/depstest/dependencies.txt
@@ -18,7 +18,7 @@ system_symbols:
# C
PIC system_misc system_debug malloc_functions ubsan
c_strings c_string_formatting
- floating_point trigonometry
+ int_functions floating_point trigonometry
stdlib_qsort
pthread system_locale
stdio_input stdio_output file_io readlink_function dir_io mmap_functions dlfcn
@@ -58,8 +58,11 @@ group: c_string_formatting
# Additional symbols in an optimized build.
__sprintf_chk
+group: int_functions
+ div
+
group: floating_point
- abs fabs floor ceil modf fmod log pow round sqrt
+ abs fabs floor ceil modf fmod log pow round sqrt trunc
group: trigonometry
acos asin atan atan2 cos sin tan
@@ -154,6 +157,7 @@ library: common
unistr_props unistr_case unistr_case_locale unistr_titlecase_brkiter unistr_cnv
cstr
uniset_core uniset_props uniset_closure usetiter uset uset_props
+ static_unicode_sets
uiter edits
ucasemap ucasemap_titlecase_brkiter script_runs
uprops ubidi_props ucase uscript uscript_props
@@ -281,6 +285,11 @@ group: punycode
deps
platform
+group: static_unicode_sets
+ static_unicode_sets.o
+ deps
+ resourcebundle uniset_props
+
group: uset_props
uset_props.o
deps
@@ -475,6 +484,8 @@ group: ustr_titlecase_brkiter
group: edits
edits.o
deps
+ # Edits::Iterator::toString() calls ICU_Utility::appendNumber()
+ icu_utility
platform
group: ucasemap_titlecase_brkiter
@@ -574,6 +585,7 @@ group: currency
deps
loclikely resourcebundle ulist ustring_case_locale
stdlib_qsort # for ucurr.o (which does not use ICU's uarrsort.o)
+ static_unicode_sets usetiter
group: icudataver # u_getDataVersion()
icudataver.o
@@ -804,7 +816,7 @@ library: i18n
alphabetic_index collation collation_builder string_search
dayperiodrules
formatting formattable_cnv regex regex_cnv translit
- double_conversion numberformatter
+ double_conversion number_representation numberformatter numberparser
universal_time_scale
uclean_i18n
@@ -881,39 +893,57 @@ group: dayperiodrules
group: double_conversion
double-conversion.o double-conversion-bignum.o double-conversion-bignum-dtoa.o
double-conversion-cached-powers.o double-conversion-diy-fp.o
- double-conversion-fast-dtoa.o
+ double-conversion-fast-dtoa.o double-conversion-strtod.o
deps
platform
+group: number_representation
+ number_decimalquantity.o number_stringbuilder.o numparse_stringsegment.o number_utils.o
+ deps
+ decnumber double_conversion
+ # for data loading; that could be split off
+ resourcebundle
+ int_functions
+ ucase uniset_core
+
group: numberformatter
# ICU 60+ NumberFormatter API
- number_affixutils.o number_compact.o number_decimalquantity.o
- number_decimfmtprops.o number_fluent.o number_formatimpl.o
+ number_affixutils.o number_asformat.o
+ number_capi.o number_compact.o number_currencysymbols.o
+ number_decimfmtprops.o
+ number_fluent.o number_formatimpl.o
number_grouping.o number_integerwidth.o number_longnames.o
- number_modifiers.o number_notation.o number_padding.o
+ number_mapper.o number_modifiers.o number_multiplier.o
+ number_notation.o number_padding.o
number_patternmodifier.o number_patternstring.o number_rounding.o
- number_scientific.o number_stringbuilder.o
+ number_scientific.o number_skeletons.o
+ currpinf.o dcfmtsym.o numsys.o
+ # pluralrules
+ standardplural.o plurrule.o
deps
- digitlist formattable format units
- # TODO: fix: dependency on formatting needed for circular dependency pluralrules <-> decimfmt.o
- # We should be able to have a small pluralrules group and depend on that here.
- formatting
+ decnumber double_conversion formattable format units
+ number_representation
uclean_i18n common
+group: numberparser
+ numparse_affixes.o numparse_compositions.o numparse_currency.o
+ numparse_decimal.o numparse_impl.o numparse_parsednumber.o
+ numparse_scientific.o numparse_symbols.o
+ numparse_validators.o
+ deps
+ numberformatter
+
group: formatting
# TODO: Try to subdivide this ball of wax.
# currencyformat
- curramt.o currfmt.o currpinf.o
+ curramt.o currfmt.o
+ # pluralrules C API
+ upluralrules.o
# decimalformat
- dcfmtsym.o numsys.o unumsys.o
- affixpatternparser.o decimfmtimpl.o digitaffix.o digitaffixesandpadding.o
- digitformatter.o digitgrouping.o digitinterval.o
- pluralaffix.o precision.o smallintformatter.o valueformatter.o
- decfmtst.o decimfmt.o decimalformatpattern.o compactdecimalformat.o
+ unumsys.o
+ decimfmt.o compactdecimalformat.o
numfmt.o unum.o
winnmfmt.o
- # pluralrules
- standardplural.o plurrule.o upluralrules.o
# scientificnumberformatter - would depend on dcfmtsym, so would be circular.
scientificnumberformatter.o
# rbnf
@@ -934,7 +964,7 @@ group: formatting
# messageformat
choicfmt.o msgfmt.o plurfmt.o selfmt.o umsg.o
deps
- digitlist formattable format units
+ decnumber formattable format units numberformatter numberparser
dayperiodrules
collation collation_builder # for rbnf
common
@@ -953,8 +983,8 @@ group: units
deps
stringenumeration
-group: digitlist
- digitlst.o decContext.o decNumber.o visibledigits.o
+group: decnumber
+ decContext.o decNumber.o
deps
double_conversion uclean_i18n
@@ -962,7 +992,7 @@ group: formattable
fmtable.o
measure.o
deps
- digitlist
+ decnumber number_representation
group: formattable_cnv
fmtable_cnv.o
diff --git a/icu4c/source/test/intltest/numbertest_api.cpp b/icu4c/source/test/intltest/numbertest_api.cpp
index e6fe8242bd3..2885f25203b 100644
--- a/icu4c/source/test/intltest/numbertest_api.cpp
+++ b/icu4c/source/test/intltest/numbertest_api.cpp
@@ -10,6 +10,7 @@
#include
#include "unicode/unum.h"
#include "unicode/numberformatter.h"
+#include "number_asformat.h"
#include "number_types.h"
#include "number_utils.h"
#include "numbertest.h"
diff --git a/icu4c/source/test/intltest/numbertest_decimalquantity.cpp b/icu4c/source/test/intltest/numbertest_decimalquantity.cpp
index cd62ac7ee9b..48b9f91e27a 100644
--- a/icu4c/source/test/intltest/numbertest_decimalquantity.cpp
+++ b/icu4c/source/test/intltest/numbertest_decimalquantity.cpp
@@ -6,6 +6,7 @@
#if !UCONFIG_NO_FORMATTING
#include "number_decimalquantity.h"
+#include "number_decnum.h"
#include "math.h"
#include
#include "number_utils.h"
diff --git a/icu4c/source/test/intltest/numbertest_patternmodifier.cpp b/icu4c/source/test/intltest/numbertest_patternmodifier.cpp
index f9e08ae96c8..13a25545d3c 100644
--- a/icu4c/source/test/intltest/numbertest_patternmodifier.cpp
+++ b/icu4c/source/test/intltest/numbertest_patternmodifier.cpp
@@ -6,6 +6,7 @@
#if !UCONFIG_NO_FORMATTING
#include "numbertest.h"
+#include "number_microprops.h"
#include "number_patternmodifier.h"
void PatternModifierTest::runIndexedTest(int32_t index, UBool exec, const char *&name, char *) {