mirror of
https://github.com/unicode-org/icu.git
synced 2025-04-13 17:01:16 +00:00
ICU-11276 Rewriring NumberFormatterImpl to expose information needed for NumberRangeFormatter.
This commit is contained in:
parent
8210f9e7d3
commit
083fe73d6b
3 changed files with 82 additions and 55 deletions
icu4c/source/i18n
|
@ -657,9 +657,9 @@ LocalizedNumberFormatter::formatDecimalQuantity(const DecimalQuantity& dq, UErro
|
|||
|
||||
void LocalizedNumberFormatter::formatImpl(impl::UFormattedNumberData* results, UErrorCode& status) const {
|
||||
if (computeCompiled(status)) {
|
||||
fCompiled->apply(results->quantity, results->string, status);
|
||||
fCompiled->format(results->quantity, results->string, status);
|
||||
} else {
|
||||
NumberFormatterImpl::applyStatic(fMacros, results->quantity, results->string, status);
|
||||
NumberFormatterImpl::formatStatic(fMacros, results->quantity, results->string, status);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -71,10 +71,13 @@ NumberFormatterImpl* NumberFormatterImpl::fromMacros(const MacroProps& macros, U
|
|||
return new NumberFormatterImpl(macros, true, status);
|
||||
}
|
||||
|
||||
void NumberFormatterImpl::applyStatic(const MacroProps& macros, DecimalQuantity& inValue,
|
||||
NumberStringBuilder& outString, UErrorCode& status) {
|
||||
void NumberFormatterImpl::formatStatic(const MacroProps& macros, DecimalQuantity& inValue,
|
||||
NumberStringBuilder& outString, UErrorCode& status) {
|
||||
NumberFormatterImpl impl(macros, false, status);
|
||||
impl.applyUnsafe(inValue, outString, status);
|
||||
MicroProps& micros = impl.preProcessUnsafe(inValue, status);
|
||||
if (U_FAILURE(status)) { return; }
|
||||
int32_t length = formatNumber(micros, inValue, outString, 0, status);
|
||||
writeAffixes(micros, outString, 0, length, status);
|
||||
}
|
||||
|
||||
int32_t NumberFormatterImpl::getPrefixSuffixStatic(const MacroProps& macros, int8_t signum,
|
||||
|
@ -89,22 +92,35 @@ int32_t NumberFormatterImpl::getPrefixSuffixStatic(const MacroProps& macros, int
|
|||
// The "unsafe" method simply re-uses fMicros, eliminating the extra copy operation.
|
||||
// See MicroProps::processQuantity() for details.
|
||||
|
||||
void NumberFormatterImpl::apply(DecimalQuantity& inValue, NumberStringBuilder& outString,
|
||||
void NumberFormatterImpl::format(DecimalQuantity& inValue, NumberStringBuilder& outString,
|
||||
UErrorCode& status) const {
|
||||
if (U_FAILURE(status)) { return; }
|
||||
MicroProps micros;
|
||||
if (!fMicroPropsGenerator) { return; }
|
||||
fMicroPropsGenerator->processQuantity(inValue, micros, status);
|
||||
preProcess(inValue, micros, status);
|
||||
if (U_FAILURE(status)) { return; }
|
||||
microsToString(micros, inValue, outString, status);
|
||||
int32_t length = formatNumber(micros, inValue, outString, 0, status);
|
||||
writeAffixes(micros, outString, 0, length, status);
|
||||
}
|
||||
|
||||
void NumberFormatterImpl::applyUnsafe(DecimalQuantity& inValue, NumberStringBuilder& outString,
|
||||
UErrorCode& status) {
|
||||
void NumberFormatterImpl::preProcess(DecimalQuantity& inValue, MicroProps& microsOut,
|
||||
UErrorCode& status) const {
|
||||
if (U_FAILURE(status)) { return; }
|
||||
if (fMicroPropsGenerator == nullptr) {
|
||||
status = U_INTERNAL_PROGRAM_ERROR;
|
||||
return;
|
||||
}
|
||||
fMicroPropsGenerator->processQuantity(inValue, microsOut, status);
|
||||
}
|
||||
|
||||
MicroProps& NumberFormatterImpl::preProcessUnsafe(DecimalQuantity& inValue, UErrorCode& status) {
|
||||
if (U_FAILURE(status)) {
|
||||
return fMicros; // must always return a value
|
||||
}
|
||||
if (fMicroPropsGenerator == nullptr) {
|
||||
status = U_INTERNAL_PROGRAM_ERROR;
|
||||
return fMicros; // must always return a value
|
||||
}
|
||||
fMicroPropsGenerator->processQuantity(inValue, fMicros, status);
|
||||
if (U_FAILURE(status)) { return; }
|
||||
microsToString(fMicros, inValue, outString, status);
|
||||
return fMicros;
|
||||
}
|
||||
|
||||
int32_t NumberFormatterImpl::getPrefixSuffix(int8_t signum, StandardPlural::Form plural,
|
||||
|
@ -404,50 +420,55 @@ NumberFormatterImpl::resolvePluralRules(const PluralRules* rulesPtr, const Local
|
|||
return fRules.getAlias();
|
||||
}
|
||||
|
||||
int32_t NumberFormatterImpl::microsToString(const MicroProps& micros, DecimalQuantity& quantity,
|
||||
NumberStringBuilder& string, UErrorCode& status) {
|
||||
int32_t NumberFormatterImpl::formatNumber(const MicroProps& micros, DecimalQuantity& quantity,
|
||||
NumberStringBuilder& string, int32_t index,
|
||||
UErrorCode& status) {
|
||||
micros.rounder.apply(quantity, status);
|
||||
micros.integerWidth.apply(quantity, status);
|
||||
int32_t length = writeNumber(micros, quantity, string, status);
|
||||
// NOTE: When range formatting is added, these modifiers can bubble up.
|
||||
// For now, apply them all here at once.
|
||||
int32_t length = writeNumber(micros, quantity, string, index, status);
|
||||
return length;
|
||||
}
|
||||
|
||||
int32_t NumberFormatterImpl::writeAffixes(const MicroProps& micros, NumberStringBuilder& string,
|
||||
int32_t start, int32_t end, UErrorCode& status) {
|
||||
// Always apply the inner modifier (which is "strong").
|
||||
length += micros.modInner->apply(string, 0, length, status);
|
||||
int32_t length = micros.modInner->apply(string, start, end, status);
|
||||
if (micros.padding.isValid()) {
|
||||
length += micros.padding
|
||||
.padAndApply(*micros.modMiddle, *micros.modOuter, string, 0, length, status);
|
||||
.padAndApply(*micros.modMiddle, *micros.modOuter, string, start, length + end, status);
|
||||
} else {
|
||||
length += micros.modMiddle->apply(string, 0, length, status);
|
||||
length += micros.modOuter->apply(string, 0, length, status);
|
||||
length += micros.modMiddle->apply(string, start, length + end, status);
|
||||
length += micros.modOuter->apply(string, start, length + end, status);
|
||||
}
|
||||
return length;
|
||||
}
|
||||
|
||||
int32_t NumberFormatterImpl::writeNumber(const MicroProps& micros, DecimalQuantity& quantity,
|
||||
NumberStringBuilder& string, UErrorCode& status) {
|
||||
NumberStringBuilder& string, int32_t index,
|
||||
UErrorCode& status) {
|
||||
int32_t length = 0;
|
||||
if (quantity.isInfinite()) {
|
||||
length += string.insert(
|
||||
length,
|
||||
length + index,
|
||||
micros.symbols->getSymbol(DecimalFormatSymbols::ENumberFormatSymbol::kInfinitySymbol),
|
||||
UNUM_INTEGER_FIELD,
|
||||
status);
|
||||
|
||||
} else if (quantity.isNaN()) {
|
||||
length += string.insert(
|
||||
length,
|
||||
length + index,
|
||||
micros.symbols->getSymbol(DecimalFormatSymbols::ENumberFormatSymbol::kNaNSymbol),
|
||||
UNUM_INTEGER_FIELD,
|
||||
status);
|
||||
|
||||
} else {
|
||||
// Add the integer digits
|
||||
length += writeIntegerDigits(micros, quantity, string, status);
|
||||
length += writeIntegerDigits(micros, quantity, string, length + index, status);
|
||||
|
||||
// Add the decimal point
|
||||
if (quantity.getLowerDisplayMagnitude() < 0 || micros.decimal == UNUM_DECIMAL_SEPARATOR_ALWAYS) {
|
||||
length += string.insert(
|
||||
length,
|
||||
length + index,
|
||||
micros.useCurrency ? micros.symbols->getSymbol(
|
||||
DecimalFormatSymbols::ENumberFormatSymbol::kMonetarySeparatorSymbol) : micros
|
||||
.symbols
|
||||
|
@ -458,21 +479,22 @@ int32_t NumberFormatterImpl::writeNumber(const MicroProps& micros, DecimalQuanti
|
|||
}
|
||||
|
||||
// Add the fraction digits
|
||||
length += writeFractionDigits(micros, quantity, string, status);
|
||||
length += writeFractionDigits(micros, quantity, string, length + index, status);
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
int32_t NumberFormatterImpl::writeIntegerDigits(const MicroProps& micros, DecimalQuantity& quantity,
|
||||
NumberStringBuilder& string, UErrorCode& status) {
|
||||
NumberStringBuilder& string, int32_t index,
|
||||
UErrorCode& status) {
|
||||
int length = 0;
|
||||
int integerCount = quantity.getUpperDisplayMagnitude() + 1;
|
||||
for (int i = 0; i < integerCount; i++) {
|
||||
// Add grouping separator
|
||||
if (micros.grouping.groupAtPosition(i, quantity)) {
|
||||
length += string.insert(
|
||||
0,
|
||||
index,
|
||||
micros.useCurrency ? micros.symbols->getSymbol(
|
||||
DecimalFormatSymbols::ENumberFormatSymbol::kMonetaryGroupingSeparatorSymbol)
|
||||
: micros.symbols->getSymbol(
|
||||
|
@ -484,20 +506,21 @@ int32_t NumberFormatterImpl::writeIntegerDigits(const MicroProps& micros, Decima
|
|||
// Get and append the next digit value
|
||||
int8_t nextDigit = quantity.getDigit(i);
|
||||
length += utils::insertDigitFromSymbols(
|
||||
string, 0, nextDigit, *micros.symbols, UNUM_INTEGER_FIELD, status);
|
||||
string, index, nextDigit, *micros.symbols, UNUM_INTEGER_FIELD, status);
|
||||
}
|
||||
return length;
|
||||
}
|
||||
|
||||
int32_t NumberFormatterImpl::writeFractionDigits(const MicroProps& micros, DecimalQuantity& quantity,
|
||||
NumberStringBuilder& string, UErrorCode& status) {
|
||||
NumberStringBuilder& string, int32_t index,
|
||||
UErrorCode& status) {
|
||||
int length = 0;
|
||||
int fractionCount = -quantity.getLowerDisplayMagnitude();
|
||||
for (int i = 0; i < fractionCount; i++) {
|
||||
// Get and append the next digit value
|
||||
int8_t nextDigit = quantity.getDigit(-i - 1);
|
||||
length += utils::insertDigitFromSymbols(
|
||||
string, string.length(), nextDigit, *micros.symbols, UNUM_FRACTION_FIELD, status);
|
||||
string, length + index, nextDigit, *micros.symbols, UNUM_FRACTION_FIELD, status);
|
||||
}
|
||||
return length;
|
||||
}
|
||||
|
|
|
@ -35,8 +35,8 @@ class NumberFormatterImpl : public UMemory {
|
|||
* Builds and evaluates an "unsafe" MicroPropsGenerator, which is cheaper but can be used only once.
|
||||
*/
|
||||
static void
|
||||
applyStatic(const MacroProps ¯os, DecimalQuantity &inValue, NumberStringBuilder &outString,
|
||||
UErrorCode &status);
|
||||
formatStatic(const MacroProps ¯os, DecimalQuantity &inValue, NumberStringBuilder &outString,
|
||||
UErrorCode &status);
|
||||
|
||||
/**
|
||||
* Prints only the prefix and suffix; used for DecimalFormat getters.
|
||||
|
@ -51,7 +51,12 @@ class NumberFormatterImpl : public UMemory {
|
|||
/**
|
||||
* Evaluates the "safe" MicroPropsGenerator created by "fromMacros".
|
||||
*/
|
||||
void apply(DecimalQuantity& inValue, NumberStringBuilder& outString, UErrorCode& status) const;
|
||||
void format(DecimalQuantity& inValue, NumberStringBuilder& outString, UErrorCode& status) const;
|
||||
|
||||
/**
|
||||
* Like format(), but saves the result into an output MicroProps without additional processing.
|
||||
*/
|
||||
void preProcess(DecimalQuantity& inValue, MicroProps& microsOut, UErrorCode& status) const;
|
||||
|
||||
/**
|
||||
* Like getPrefixSuffixStatic() but uses the safe compiled object.
|
||||
|
@ -59,6 +64,19 @@ class NumberFormatterImpl : public UMemory {
|
|||
int32_t getPrefixSuffix(int8_t signum, StandardPlural::Form plural, NumberStringBuilder& outString,
|
||||
UErrorCode& status) const;
|
||||
|
||||
/**
|
||||
* Synthesizes the output string from a MicroProps and DecimalQuantity.
|
||||
* This method formats only the main number, not affixes.
|
||||
*/
|
||||
static int32_t formatNumber(const MicroProps& micros, DecimalQuantity& quantity,
|
||||
NumberStringBuilder& string, int32_t index, UErrorCode& status);
|
||||
|
||||
/**
|
||||
* Adds the affixes. Intended to be called immediately after formatNumber.
|
||||
*/
|
||||
static int32_t writeAffixes(const MicroProps& micros, NumberStringBuilder& string, int32_t start,
|
||||
int32_t end, UErrorCode& status);
|
||||
|
||||
private:
|
||||
// Head of the MicroPropsGenerator linked list:
|
||||
const MicroPropsGenerator *fMicroPropsGenerator = nullptr;
|
||||
|
@ -85,7 +103,7 @@ class NumberFormatterImpl : public UMemory {
|
|||
|
||||
NumberFormatterImpl(const MacroProps ¯os, bool safe, UErrorCode &status);
|
||||
|
||||
void applyUnsafe(DecimalQuantity &inValue, NumberStringBuilder &outString, UErrorCode &status);
|
||||
MicroProps& preProcessUnsafe(DecimalQuantity &inValue, UErrorCode &status);
|
||||
|
||||
int32_t getPrefixSuffixUnsafe(int8_t signum, StandardPlural::Form plural,
|
||||
NumberStringBuilder& outString, UErrorCode& status);
|
||||
|
@ -113,31 +131,17 @@ class NumberFormatterImpl : public UMemory {
|
|||
const MicroPropsGenerator *
|
||||
macrosToMicroGenerator(const MacroProps ¯os, bool safe, UErrorCode &status);
|
||||
|
||||
/**
|
||||
* Synthesizes the output string from a MicroProps and DecimalQuantity.
|
||||
*
|
||||
* @param micros
|
||||
* The MicroProps after the quantity has been consumed. Will not be mutated.
|
||||
* @param quantity
|
||||
* The DecimalQuantity to be rendered. May be mutated.
|
||||
* @param string
|
||||
* The output string. Will be mutated.
|
||||
*/
|
||||
static int32_t
|
||||
microsToString(const MicroProps µs, DecimalQuantity &quantity, NumberStringBuilder &string,
|
||||
UErrorCode &status);
|
||||
|
||||
static int32_t
|
||||
writeNumber(const MicroProps µs, DecimalQuantity &quantity, NumberStringBuilder &string,
|
||||
UErrorCode &status);
|
||||
int32_t index, UErrorCode &status);
|
||||
|
||||
static int32_t
|
||||
writeIntegerDigits(const MicroProps µs, DecimalQuantity &quantity, NumberStringBuilder &string,
|
||||
UErrorCode &status);
|
||||
int32_t index, UErrorCode &status);
|
||||
|
||||
static int32_t
|
||||
writeFractionDigits(const MicroProps µs, DecimalQuantity &quantity, NumberStringBuilder &string,
|
||||
UErrorCode &status);
|
||||
int32_t index, UErrorCode &status);
|
||||
};
|
||||
|
||||
} // namespace impl
|
||||
|
|
Loading…
Add table
Reference in a new issue