ICU-11276 Rewriring NumberFormatterImpl to expose information needed for NumberRangeFormatter.

This commit is contained in:
Shane Carr 2018-09-05 15:23:36 -07:00
parent 8210f9e7d3
commit 083fe73d6b
No known key found for this signature in database
GPG key ID: FCED3B24AAB18B5C
3 changed files with 82 additions and 55 deletions

View file

@ -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);
}
}

View file

@ -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;
}

View file

@ -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 &macros, DecimalQuantity &inValue, NumberStringBuilder &outString,
UErrorCode &status);
formatStatic(const MacroProps &macros, 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 &macros, 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 &macros, 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 &micros, DecimalQuantity &quantity, NumberStringBuilder &string,
UErrorCode &status);
static int32_t
writeNumber(const MicroProps &micros, DecimalQuantity &quantity, NumberStringBuilder &string,
UErrorCode &status);
int32_t index, UErrorCode &status);
static int32_t
writeIntegerDigits(const MicroProps &micros, DecimalQuantity &quantity, NumberStringBuilder &string,
UErrorCode &status);
int32_t index, UErrorCode &status);
static int32_t
writeFractionDigits(const MicroProps &micros, DecimalQuantity &quantity, NumberStringBuilder &string,
UErrorCode &status);
int32_t index, UErrorCode &status);
};
} // namespace impl