| Index: source/i18n/digitformatter.cpp
|
| diff --git a/source/i18n/digitformatter.cpp b/source/i18n/digitformatter.cpp
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..531eb385025488e8b9dd71e37cd8bdd79ea205e9
|
| --- /dev/null
|
| +++ b/source/i18n/digitformatter.cpp
|
| @@ -0,0 +1,415 @@
|
| +/*
|
| + * Copyright (C) 2015, International Business Machines
|
| + * Corporation and others. All Rights Reserved.
|
| + *
|
| + * file name: digitformatter.cpp
|
| + */
|
| +
|
| +#include "unicode/utypes.h"
|
| +
|
| +#if !UCONFIG_NO_FORMATTING
|
| +
|
| +#include "unicode/dcfmtsym.h"
|
| +#include "unicode/unum.h"
|
| +
|
| +#include "digitformatter.h"
|
| +#include "digitgrouping.h"
|
| +#include "digitinterval.h"
|
| +#include "digitlst.h"
|
| +#include "fphdlimp.h"
|
| +#include "smallintformatter.h"
|
| +#include "unistrappender.h"
|
| +#include "visibledigits.h"
|
| +
|
| +U_NAMESPACE_BEGIN
|
| +
|
| +DigitFormatter::DigitFormatter()
|
| + : fGroupingSeparator(",", -1, US_INV), fDecimal(".", -1, US_INV),
|
| + fNegativeSign("-", -1, US_INV), fPositiveSign("+", -1, US_INV),
|
| + fIsStandardDigits(TRUE), fExponent("E", -1, US_INV) {
|
| + for (int32_t i = 0; i < 10; ++i) {
|
| + fLocalizedDigits[i] = (UChar32) (0x30 + i);
|
| + }
|
| + fInfinity.setTo(UnicodeString("Inf", -1, US_INV), UNUM_INTEGER_FIELD);
|
| + fNan.setTo(UnicodeString("Nan", -1, US_INV), UNUM_INTEGER_FIELD);
|
| +}
|
| +
|
| +DigitFormatter::DigitFormatter(const DecimalFormatSymbols &symbols) {
|
| + setDecimalFormatSymbols(symbols);
|
| +}
|
| +
|
| +void
|
| +DigitFormatter::setOtherDecimalFormatSymbols(
|
| + const DecimalFormatSymbols &symbols) {
|
| + fLocalizedDigits[0] = symbols.getConstSymbol(DecimalFormatSymbols::kZeroDigitSymbol).char32At(0);
|
| + fLocalizedDigits[1] = symbols.getConstSymbol(DecimalFormatSymbols::kOneDigitSymbol).char32At(0);
|
| + fLocalizedDigits[2] = symbols.getConstSymbol(DecimalFormatSymbols::kTwoDigitSymbol).char32At(0);
|
| + fLocalizedDigits[3] = symbols.getConstSymbol(DecimalFormatSymbols::kThreeDigitSymbol).char32At(0);
|
| + fLocalizedDigits[4] = symbols.getConstSymbol(DecimalFormatSymbols::kFourDigitSymbol).char32At(0);
|
| + fLocalizedDigits[5] = symbols.getConstSymbol(DecimalFormatSymbols::kFiveDigitSymbol).char32At(0);
|
| + fLocalizedDigits[6] = symbols.getConstSymbol(DecimalFormatSymbols::kSixDigitSymbol).char32At(0);
|
| + fLocalizedDigits[7] = symbols.getConstSymbol(DecimalFormatSymbols::kSevenDigitSymbol).char32At(0);
|
| + fLocalizedDigits[8] = symbols.getConstSymbol(DecimalFormatSymbols::kEightDigitSymbol).char32At(0);
|
| + fLocalizedDigits[9] = symbols.getConstSymbol(DecimalFormatSymbols::kNineDigitSymbol).char32At(0);
|
| + fIsStandardDigits = isStandardDigits();
|
| + fNegativeSign = symbols.getConstSymbol(DecimalFormatSymbols::kMinusSignSymbol);
|
| + fPositiveSign = symbols.getConstSymbol(DecimalFormatSymbols::kPlusSignSymbol);
|
| + fInfinity.setTo(symbols.getConstSymbol(DecimalFormatSymbols::kInfinitySymbol), UNUM_INTEGER_FIELD);
|
| + fNan.setTo(symbols.getConstSymbol(DecimalFormatSymbols::kNaNSymbol), UNUM_INTEGER_FIELD);
|
| + fExponent = symbols.getConstSymbol(DecimalFormatSymbols::kExponentialSymbol);
|
| +}
|
| +
|
| +void
|
| +DigitFormatter::setDecimalFormatSymbolsForMonetary(
|
| + const DecimalFormatSymbols &symbols) {
|
| + setOtherDecimalFormatSymbols(symbols);
|
| + fGroupingSeparator = symbols.getConstSymbol(DecimalFormatSymbols::kMonetaryGroupingSeparatorSymbol);
|
| + fDecimal = symbols.getConstSymbol(DecimalFormatSymbols::kMonetarySeparatorSymbol);
|
| +}
|
| +
|
| +void
|
| +DigitFormatter::setDecimalFormatSymbols(
|
| + const DecimalFormatSymbols &symbols) {
|
| + setOtherDecimalFormatSymbols(symbols);
|
| + fGroupingSeparator = symbols.getConstSymbol(DecimalFormatSymbols::kGroupingSeparatorSymbol);
|
| + fDecimal = symbols.getConstSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol);
|
| +}
|
| +
|
| +static void appendField(
|
| + int32_t fieldId,
|
| + const UnicodeString &value,
|
| + FieldPositionHandler &handler,
|
| + UnicodeString &appendTo) {
|
| + int32_t currentLength = appendTo.length();
|
| + appendTo.append(value);
|
| + handler.addAttribute(
|
| + fieldId,
|
| + currentLength,
|
| + appendTo.length());
|
| +}
|
| +
|
| +int32_t DigitFormatter::countChar32(
|
| + const DigitGrouping &grouping,
|
| + const DigitInterval &interval,
|
| + const DigitFormatterOptions &options) const {
|
| + int32_t result = interval.length();
|
| +
|
| + // We always emit '0' in lieu of no digits.
|
| + if (result == 0) {
|
| + result = 1;
|
| + }
|
| + if (options.fAlwaysShowDecimal || interval.getLeastSignificantInclusive() < 0) {
|
| + result += fDecimal.countChar32();
|
| + }
|
| + result += grouping.getSeparatorCount(interval.getIntDigitCount()) * fGroupingSeparator.countChar32();
|
| + return result;
|
| +}
|
| +
|
| +int32_t
|
| +DigitFormatter::countChar32(
|
| + const VisibleDigits &digits,
|
| + const DigitGrouping &grouping,
|
| + const DigitFormatterOptions &options) const {
|
| + if (digits.isNaN()) {
|
| + return countChar32ForNaN();
|
| + }
|
| + if (digits.isInfinite()) {
|
| + return countChar32ForInfinity();
|
| + }
|
| + return countChar32(
|
| + grouping,
|
| + digits.getInterval(),
|
| + options);
|
| +}
|
| +
|
| +int32_t
|
| +DigitFormatter::countChar32(
|
| + const VisibleDigitsWithExponent &digits,
|
| + const SciFormatterOptions &options) const {
|
| + if (digits.isNaN()) {
|
| + return countChar32ForNaN();
|
| + }
|
| + if (digits.isInfinite()) {
|
| + return countChar32ForInfinity();
|
| + }
|
| + const VisibleDigits *exponent = digits.getExponent();
|
| + if (exponent == NULL) {
|
| + DigitGrouping grouping;
|
| + return countChar32(
|
| + grouping,
|
| + digits.getMantissa().getInterval(),
|
| + options.fMantissa);
|
| + }
|
| + return countChar32(
|
| + *exponent, digits.getMantissa().getInterval(), options);
|
| +}
|
| +
|
| +int32_t
|
| +DigitFormatter::countChar32(
|
| + const VisibleDigits &exponent,
|
| + const DigitInterval &mantissaInterval,
|
| + const SciFormatterOptions &options) const {
|
| + DigitGrouping grouping;
|
| + int32_t count = countChar32(
|
| + grouping, mantissaInterval, options.fMantissa);
|
| + count += fExponent.countChar32();
|
| + count += countChar32ForExponent(
|
| + exponent, options.fExponent);
|
| + return count;
|
| +}
|
| +
|
| +UnicodeString &DigitFormatter::format(
|
| + const VisibleDigits &digits,
|
| + const DigitGrouping &grouping,
|
| + const DigitFormatterOptions &options,
|
| + FieldPositionHandler &handler,
|
| + UnicodeString &appendTo) const {
|
| + if (digits.isNaN()) {
|
| + return formatNaN(handler, appendTo);
|
| + }
|
| + if (digits.isInfinite()) {
|
| + return formatInfinity(handler, appendTo);
|
| + }
|
| +
|
| + const DigitInterval &interval = digits.getInterval();
|
| + int32_t digitsLeftOfDecimal = interval.getMostSignificantExclusive();
|
| + int32_t lastDigitPos = interval.getLeastSignificantInclusive();
|
| + int32_t intBegin = appendTo.length();
|
| + int32_t fracBegin;
|
| +
|
| + // Emit "0" instead of empty string.
|
| + if (digitsLeftOfDecimal == 0 && lastDigitPos == 0) {
|
| + appendTo.append(fLocalizedDigits[0]);
|
| + handler.addAttribute(UNUM_INTEGER_FIELD, intBegin, appendTo.length());
|
| + if (options.fAlwaysShowDecimal) {
|
| + appendField(
|
| + UNUM_DECIMAL_SEPARATOR_FIELD,
|
| + fDecimal,
|
| + handler,
|
| + appendTo);
|
| + }
|
| + return appendTo;
|
| + }
|
| + {
|
| + UnicodeStringAppender appender(appendTo);
|
| + for (int32_t i = interval.getMostSignificantExclusive() - 1;
|
| + i >= interval.getLeastSignificantInclusive(); --i) {
|
| + if (i == -1) {
|
| + appender.flush();
|
| + appendField(
|
| + UNUM_DECIMAL_SEPARATOR_FIELD,
|
| + fDecimal,
|
| + handler,
|
| + appendTo);
|
| + fracBegin = appendTo.length();
|
| + }
|
| + appender.append(fLocalizedDigits[digits.getDigitByExponent(i)]);
|
| + if (grouping.isSeparatorAt(digitsLeftOfDecimal, i)) {
|
| + appender.flush();
|
| + appendField(
|
| + UNUM_GROUPING_SEPARATOR_FIELD,
|
| + fGroupingSeparator,
|
| + handler,
|
| + appendTo);
|
| + }
|
| + if (i == 0) {
|
| + appender.flush();
|
| + if (digitsLeftOfDecimal > 0) {
|
| + handler.addAttribute(UNUM_INTEGER_FIELD, intBegin, appendTo.length());
|
| + }
|
| + }
|
| + }
|
| + if (options.fAlwaysShowDecimal && lastDigitPos == 0) {
|
| + appender.flush();
|
| + appendField(
|
| + UNUM_DECIMAL_SEPARATOR_FIELD,
|
| + fDecimal,
|
| + handler,
|
| + appendTo);
|
| + }
|
| + }
|
| + // lastDigitPos is never > 0 so we are guaranteed that kIntegerField
|
| + // is already added.
|
| + if (lastDigitPos < 0) {
|
| + handler.addAttribute(UNUM_FRACTION_FIELD, fracBegin, appendTo.length());
|
| + }
|
| + return appendTo;
|
| +}
|
| +
|
| +UnicodeString &
|
| +DigitFormatter::format(
|
| + const VisibleDigitsWithExponent &digits,
|
| + const SciFormatterOptions &options,
|
| + FieldPositionHandler &handler,
|
| + UnicodeString &appendTo) const {
|
| + DigitGrouping grouping;
|
| + format(
|
| + digits.getMantissa(),
|
| + grouping,
|
| + options.fMantissa,
|
| + handler,
|
| + appendTo);
|
| + const VisibleDigits *exponent = digits.getExponent();
|
| + if (exponent == NULL) {
|
| + return appendTo;
|
| + }
|
| + int32_t expBegin = appendTo.length();
|
| + appendTo.append(fExponent);
|
| + handler.addAttribute(
|
| + UNUM_EXPONENT_SYMBOL_FIELD, expBegin, appendTo.length());
|
| + return formatExponent(
|
| + *exponent,
|
| + options.fExponent,
|
| + UNUM_EXPONENT_SIGN_FIELD,
|
| + UNUM_EXPONENT_FIELD,
|
| + handler,
|
| + appendTo);
|
| +}
|
| +
|
| +static int32_t formatInt(
|
| + int32_t value, uint8_t *digits) {
|
| + int32_t idx = 0;
|
| + while (value > 0) {
|
| + digits[idx++] = (uint8_t) (value % 10);
|
| + value /= 10;
|
| + }
|
| + return idx;
|
| +}
|
| +
|
| +UnicodeString &
|
| +DigitFormatter::formatDigits(
|
| + const uint8_t *digits,
|
| + int32_t count,
|
| + const IntDigitCountRange &range,
|
| + int32_t intField,
|
| + FieldPositionHandler &handler,
|
| + UnicodeString &appendTo) const {
|
| + int32_t i = range.pin(count) - 1;
|
| + int32_t begin = appendTo.length();
|
| +
|
| + // Always emit '0' as placeholder for empty string.
|
| + if (i == -1) {
|
| + appendTo.append(fLocalizedDigits[0]);
|
| + handler.addAttribute(intField, begin, appendTo.length());
|
| + return appendTo;
|
| + }
|
| + {
|
| + UnicodeStringAppender appender(appendTo);
|
| + for (; i >= count; --i) {
|
| + appender.append(fLocalizedDigits[0]);
|
| + }
|
| + for (; i >= 0; --i) {
|
| + appender.append(fLocalizedDigits[digits[i]]);
|
| + }
|
| + }
|
| + handler.addAttribute(intField, begin, appendTo.length());
|
| + return appendTo;
|
| +}
|
| +
|
| +UnicodeString &
|
| +DigitFormatter::formatExponent(
|
| + const VisibleDigits &digits,
|
| + const DigitFormatterIntOptions &options,
|
| + int32_t signField,
|
| + int32_t intField,
|
| + FieldPositionHandler &handler,
|
| + UnicodeString &appendTo) const {
|
| + UBool neg = digits.isNegative();
|
| + if (neg || options.fAlwaysShowSign) {
|
| + appendField(
|
| + signField,
|
| + neg ? fNegativeSign : fPositiveSign,
|
| + handler,
|
| + appendTo);
|
| + }
|
| + int32_t begin = appendTo.length();
|
| + DigitGrouping grouping;
|
| + DigitFormatterOptions expOptions;
|
| + FieldPosition fpos(FieldPosition::DONT_CARE);
|
| + FieldPositionOnlyHandler noHandler(fpos);
|
| + format(
|
| + digits,
|
| + grouping,
|
| + expOptions,
|
| + noHandler,
|
| + appendTo);
|
| + handler.addAttribute(intField, begin, appendTo.length());
|
| + return appendTo;
|
| +}
|
| +
|
| +int32_t
|
| +DigitFormatter::countChar32ForExponent(
|
| + const VisibleDigits &exponent,
|
| + const DigitFormatterIntOptions &options) const {
|
| + int32_t result = 0;
|
| + UBool neg = exponent.isNegative();
|
| + if (neg || options.fAlwaysShowSign) {
|
| + result += neg ? fNegativeSign.countChar32() : fPositiveSign.countChar32();
|
| + }
|
| + DigitGrouping grouping;
|
| + DigitFormatterOptions expOptions;
|
| + result += countChar32(grouping, exponent.getInterval(), expOptions);
|
| + return result;
|
| +}
|
| +
|
| +UnicodeString &
|
| +DigitFormatter::formatPositiveInt32(
|
| + int32_t positiveValue,
|
| + const IntDigitCountRange &range,
|
| + FieldPositionHandler &handler,
|
| + UnicodeString &appendTo) const {
|
| + // super fast path
|
| + if (fIsStandardDigits && SmallIntFormatter::canFormat(positiveValue, range)) {
|
| + int32_t begin = appendTo.length();
|
| + SmallIntFormatter::format(positiveValue, range, appendTo);
|
| + handler.addAttribute(UNUM_INTEGER_FIELD, begin, appendTo.length());
|
| + return appendTo;
|
| + }
|
| + uint8_t digits[10];
|
| + int32_t count = formatInt(positiveValue, digits);
|
| + return formatDigits(
|
| + digits,
|
| + count,
|
| + range,
|
| + UNUM_INTEGER_FIELD,
|
| + handler,
|
| + appendTo);
|
| +}
|
| +
|
| +UBool DigitFormatter::isStandardDigits() const {
|
| + UChar32 cdigit = 0x30;
|
| + for (int32_t i = 0; i < UPRV_LENGTHOF(fLocalizedDigits); ++i) {
|
| + if (fLocalizedDigits[i] != cdigit) {
|
| + return FALSE;
|
| + }
|
| + ++cdigit;
|
| + }
|
| + return TRUE;
|
| +}
|
| +
|
| +UBool
|
| +DigitFormatter::equals(const DigitFormatter &rhs) const {
|
| + UBool result = (fGroupingSeparator == rhs.fGroupingSeparator) &&
|
| + (fDecimal == rhs.fDecimal) &&
|
| + (fNegativeSign == rhs.fNegativeSign) &&
|
| + (fPositiveSign == rhs.fPositiveSign) &&
|
| + (fInfinity.equals(rhs.fInfinity)) &&
|
| + (fNan.equals(rhs.fNan)) &&
|
| + (fIsStandardDigits == rhs.fIsStandardDigits) &&
|
| + (fExponent == rhs.fExponent);
|
| +
|
| + if (!result) {
|
| + return FALSE;
|
| + }
|
| + for (int32_t i = 0; i < UPRV_LENGTHOF(fLocalizedDigits); ++i) {
|
| + if (fLocalizedDigits[i] != rhs.fLocalizedDigits[i]) {
|
| + return FALSE;
|
| + }
|
| + }
|
| + return TRUE;
|
| +}
|
| +
|
| +
|
| +U_NAMESPACE_END
|
| +
|
| +#endif /* #if !UCONFIG_NO_FORMATTING */
|
|
|