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,
// 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,
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
}
// 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(
// 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;
}
* 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.
/**
* 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.
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;
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);
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