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 */ |