diff --git a/icu4c/source/i18n/decimfmt.cpp b/icu4c/source/i18n/decimfmt.cpp index 99fbfb54bd4..c50c2ca0838 100644 --- a/icu4c/source/i18n/decimfmt.cpp +++ b/icu4c/source/i18n/decimfmt.cpp @@ -9,11 +9,229 @@ // Helpful in toString methods and elsewhere. #define UNISTR_FROM_STRING_EXPLICIT +#include "unicode/decimfmt.h" +#include "number_decimalquantity.h" + using namespace icu; +using namespace icu::number; +using namespace icu::number::impl; +using ERoundingMode = icu::DecimalFormat::ERoundingMode; +using EPadPosition = icu::DecimalFormat::EPadPosition; +DecimalFormat::DecimalFormat(UErrorCode& status) {} +DecimalFormat::DecimalFormat(const UnicodeString& pattern, UErrorCode& status) {} +DecimalFormat::DecimalFormat(const UnicodeString& pattern, DecimalFormatSymbols* symbolsToAdopt, + UErrorCode& status) {} + +DecimalFormat::DecimalFormat(const UnicodeString& pattern, DecimalFormatSymbols* symbolsToAdopt, + UNumberFormatStyle style, UErrorCode& status) {} + +void DecimalFormat::setParseAllInput(UNumberFormatAttributeValue value) {} + +DecimalFormat& +DecimalFormat::setAttribute(UNumberFormatAttribute attr, int32_t newvalue, UErrorCode& status) {} + +int32_t DecimalFormat::getAttribute(UNumberFormatAttribute attr, UErrorCode& status) const {} + +void DecimalFormat::setGroupingUsed(UBool newValue) {} + +void DecimalFormat::setParseIntegerOnly(UBool value) {} + +void DecimalFormat::setContext(UDisplayContext value, UErrorCode& status) {} + +DecimalFormat::DecimalFormat(const UnicodeString& pattern, DecimalFormatSymbols* symbolsToAdopt, + UParseError& parseError, UErrorCode& status) {} + +DecimalFormat::DecimalFormat(const UnicodeString& pattern, const DecimalFormatSymbols& symbols, + UErrorCode& status) {} + +DecimalFormat::DecimalFormat(const DecimalFormat& source) {} + +DecimalFormat& DecimalFormat::operator=(const DecimalFormat& rhs) {} + +DecimalFormat::~DecimalFormat() = default; + +Format* DecimalFormat::clone() const {} + +UBool DecimalFormat::operator==(const Format& other) const {} + +UnicodeString& DecimalFormat::format(double number, UnicodeString& appendTo, FieldPosition& pos) const {} + +UnicodeString& DecimalFormat::format(double number, UnicodeString& appendTo, FieldPosition& pos, + UErrorCode& status) const {} + +UnicodeString& +DecimalFormat::format(double number, UnicodeString& appendTo, FieldPositionIterator* posIter, + UErrorCode& status) const {} + +UnicodeString& DecimalFormat::format(int32_t number, UnicodeString& appendTo, FieldPosition& pos) const {} + +UnicodeString& DecimalFormat::format(int32_t number, UnicodeString& appendTo, FieldPosition& pos, + UErrorCode& status) const {} + +UnicodeString& +DecimalFormat::format(int32_t number, UnicodeString& appendTo, FieldPositionIterator* posIter, + UErrorCode& status) const {} + +UnicodeString& DecimalFormat::format(int64_t number, UnicodeString& appendTo, FieldPosition& pos) const {} + +UnicodeString& DecimalFormat::format(int64_t number, UnicodeString& appendTo, FieldPosition& pos, + UErrorCode& status) const {} + +UnicodeString& +DecimalFormat::format(int64_t number, UnicodeString& appendTo, FieldPositionIterator* posIter, + UErrorCode& status) const {} + +UnicodeString& +DecimalFormat::format(StringPiece number, UnicodeString& appendTo, FieldPositionIterator* posIter, + UErrorCode& status) const {} + +UnicodeString& +DecimalFormat::format(const DecimalQuantity& number, UnicodeString& appendTo, FieldPositionIterator* posIter, + UErrorCode& status) const {} + +UnicodeString& DecimalFormat::format(const DecimalQuantity& number, UnicodeString& appendTo, FieldPosition& pos, + UErrorCode& status) const {} + +void +DecimalFormat::parse(const UnicodeString& text, Formattable& result, ParsePosition& parsePosition) const {} + +CurrencyAmount* DecimalFormat::parseCurrency(const UnicodeString& text, ParsePosition& pos) const {} + +const DecimalFormatSymbols* DecimalFormat::getDecimalFormatSymbols(void) const {} + +void DecimalFormat::adoptDecimalFormatSymbols(DecimalFormatSymbols* symbolsToAdopt) {} + +void DecimalFormat::setDecimalFormatSymbols(const DecimalFormatSymbols& symbols) {} + +const CurrencyPluralInfo* DecimalFormat::getCurrencyPluralInfo(void) const {} + +void DecimalFormat::adoptCurrencyPluralInfo(CurrencyPluralInfo* toAdopt) {} + +void DecimalFormat::setCurrencyPluralInfo(const CurrencyPluralInfo& info) {} + +UnicodeString& DecimalFormat::getPositivePrefix(UnicodeString& result) const {} + +void DecimalFormat::setPositivePrefix(const UnicodeString& newValue) {} + +UnicodeString& DecimalFormat::getNegativePrefix(UnicodeString& result) const {} + +void DecimalFormat::setNegativePrefix(const UnicodeString& newValue) {} + +UnicodeString& DecimalFormat::getPositiveSuffix(UnicodeString& result) const {} + +void DecimalFormat::setPositiveSuffix(const UnicodeString& newValue) {} + +UnicodeString& DecimalFormat::getNegativeSuffix(UnicodeString& result) const {} + +void DecimalFormat::setNegativeSuffix(const UnicodeString& newValue) {} + +int32_t DecimalFormat::getMultiplier(void) const {} + +void DecimalFormat::setMultiplier(int32_t newValue) {} + +double DecimalFormat::getRoundingIncrement(void) const {} + +void DecimalFormat::setRoundingIncrement(double newValue) {} + +ERoundingMode DecimalFormat::getRoundingMode(void) const {} + +void DecimalFormat::setRoundingMode(ERoundingMode roundingMode) {} + +int32_t DecimalFormat::getFormatWidth(void) const {} + +void DecimalFormat::setFormatWidth(int32_t width) {} + +UnicodeString DecimalFormat::getPadCharacterString() const {} + +void DecimalFormat::setPadCharacter(const UnicodeString& padChar) {} + +EPadPosition DecimalFormat::getPadPosition(void) const {} + +void DecimalFormat::setPadPosition(EPadPosition padPos) {} + +UBool DecimalFormat::isScientificNotation(void) const {} + +void DecimalFormat::setScientificNotation(UBool useScientific) {} + +int8_t DecimalFormat::getMinimumExponentDigits(void) const {} + +void DecimalFormat::setMinimumExponentDigits(int8_t minExpDig) {} + +UBool DecimalFormat::isExponentSignAlwaysShown(void) const {} + +void DecimalFormat::setExponentSignAlwaysShown(UBool expSignAlways) {} + +int32_t DecimalFormat::getGroupingSize(void) const {} + +void DecimalFormat::setGroupingSize(int32_t newValue) {} + +int32_t DecimalFormat::getSecondaryGroupingSize(void) const {} + +void DecimalFormat::setSecondaryGroupingSize(int32_t newValue) {} + +int32_t DecimalFormat::getMinimumGroupingDigits() const {} + +void DecimalFormat::setMinimumGroupingDigits(int32_t newValue) {} + +UBool DecimalFormat::isDecimalSeparatorAlwaysShown(void) const {} + +void DecimalFormat::setDecimalSeparatorAlwaysShown(UBool newValue) {} + +UBool DecimalFormat::isDecimalPatternMatchRequired(void) const {} + +void DecimalFormat::setDecimalPatternMatchRequired(UBool newValue) {} + +UnicodeString& DecimalFormat::toPattern(UnicodeString& result) const {} + +UnicodeString& DecimalFormat::toLocalizedPattern(UnicodeString& result) const {} + +void +DecimalFormat::applyPattern(const UnicodeString& pattern, UParseError& parseError, UErrorCode& status) {} + +void DecimalFormat::applyPattern(const UnicodeString& pattern, UErrorCode& status) {} + +void DecimalFormat::applyLocalizedPattern(const UnicodeString& pattern, UParseError& parseError, + UErrorCode& status) {} + +void DecimalFormat::applyLocalizedPattern(const UnicodeString& pattern, UErrorCode& status) {} + +void DecimalFormat::setMaximumIntegerDigits(int32_t newValue) {} + +void DecimalFormat::setMinimumIntegerDigits(int32_t newValue) {} + +void DecimalFormat::setMaximumFractionDigits(int32_t newValue) {} + +void DecimalFormat::setMinimumFractionDigits(int32_t newValue) {} + +int32_t DecimalFormat::getMinimumSignificantDigits() const {} + +int32_t DecimalFormat::getMaximumSignificantDigits() const {} + +void DecimalFormat::setMinimumSignificantDigits(int32_t min) {} + +void DecimalFormat::setMaximumSignificantDigits(int32_t max) {} + +UBool DecimalFormat::areSignificantDigitsUsed() const {} + +void DecimalFormat::setSignificantDigitsUsed(UBool useSignificantDigits) {} + +void DecimalFormat::setCurrency(const char16_t* theCurrency, UErrorCode& ec) {} + +void DecimalFormat::setCurrency(const char16_t* theCurrency) {} + +void DecimalFormat::setCurrencyUsage(UCurrencyUsage newUsage, UErrorCode* ec) {} + +UCurrencyUsage DecimalFormat::getCurrencyUsage() const {} + +number::LocalizedNumberFormatter DecimalFormat::toNumberFormatter() const {} + +UClassID DecimalFormat::getStaticClassID() {} + +UClassID DecimalFormat::getDynamicClassID() const {} #endif /* #if !UCONFIG_NO_FORMATTING */ diff --git a/icu4c/source/i18n/fmtable.cpp b/icu4c/source/i18n/fmtable.cpp index c2a398d847a..051eccf33d1 100644 --- a/icu4c/source/i18n/fmtable.cpp +++ b/icu4c/source/i18n/fmtable.cpp @@ -29,8 +29,8 @@ #include "cmemory.h" #include "cstring.h" #include "decNumber.h" -#include "digitlst.h" #include "fmtableimp.h" +#include "number_decimalquantity.h" // ***************************************************************************** // class Formattable @@ -40,6 +40,8 @@ U_NAMESPACE_BEGIN UOBJECT_DEFINE_RTTI_IMPLEMENTATION(Formattable) +using number::impl::DecimalQuantity; + //-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-. @@ -103,7 +105,7 @@ void Formattable::init() { fValue.fInt64 = 0; fType = kLong; fDecimalStr = NULL; - fDecimalNum = NULL; + fDecimalQuantity = NULL; fBogus.setToBogus(); } @@ -257,8 +259,8 @@ Formattable::operator=(const Formattable& source) } UErrorCode status = U_ZERO_ERROR; - if (source.fDecimalNum != NULL) { - fDecimalNum = new DigitList(*source.fDecimalNum); // TODO: use internal digit list + if (source.fDecimalQuantity != NULL) { + fDecimalQuantity = new DecimalQuantity(*source.fDecimalQuantity); } if (source.fDecimalStr != NULL) { fDecimalStr = new CharString(*source.fDecimalStr, status); @@ -356,14 +358,9 @@ void Formattable::dispose() delete fDecimalStr; fDecimalStr = NULL; - - FmtStackData *stackData = (FmtStackData*)fStackData; - if(fDecimalNum != &(stackData->stackDecimalNum)) { - delete fDecimalNum; - } else { - fDecimalNum->~DigitList(); // destruct, don't deallocate - } - fDecimalNum = NULL; + + delete fDecimalQuantity; + fDecimalQuantity = NULL; } Formattable * @@ -465,8 +462,8 @@ Formattable::getInt64(UErrorCode& status) const } else if (fValue.fDouble < (double)U_INT64_MIN) { status = U_INVALID_FORMAT_ERROR; return U_INT64_MIN; - } else if (fabs(fValue.fDouble) > U_DOUBLE_MAX_EXACT_INT && fDecimalNum != NULL) { - int64_t val = fDecimalNum->getInt64(); + } else if (fabs(fValue.fDouble) > U_DOUBLE_MAX_EXACT_INT && fDecimalQuantity != NULL) { + int64_t val = fDecimalQuantity->toLong(); if (val != 0) { return val; } else { @@ -714,27 +711,27 @@ StringPiece Formattable::getDecimalNumber(UErrorCode &status) { CharString *Formattable::internalGetCharString(UErrorCode &status) { if(fDecimalStr == NULL) { - if (fDecimalNum == NULL) { + if (fDecimalQuantity == NULL) { // No decimal number for the formattable yet. Which means the value was // set directly by the user as an int, int64 or double. If the value came // from parsing, or from the user setting a decimal number, fDecimalNum // would already be set. // - fDecimalNum = new DigitList; // TODO: use internal digit list - if (fDecimalNum == NULL) { + fDecimalQuantity = new DecimalQuantity(); // TODO: use internal digit list + if (fDecimalQuantity == NULL) { status = U_MEMORY_ALLOCATION_ERROR; return NULL; } switch (fType) { case kDouble: - fDecimalNum->set(this->getDouble()); + fDecimalQuantity->setToDouble(this->getDouble()); break; case kLong: - fDecimalNum->set(this->getLong()); + fDecimalQuantity->setToInt(this->getLong()); break; case kInt64: - fDecimalNum->set(this->getInt64()); + fDecimalQuantity->setToLong(this->getInt64()); break; default: // The formattable's value is not a numeric type. @@ -743,55 +740,48 @@ CharString *Formattable::internalGetCharString(UErrorCode &status) { } } - fDecimalStr = new CharString; + fDecimalStr = new CharString(); if (fDecimalStr == NULL) { status = U_MEMORY_ALLOCATION_ERROR; return NULL; } - fDecimalNum->getDecimal(*fDecimalStr, status); + UnicodeString result = fDecimalQuantity->toNumberString(); + for (int32_t i=0; iappend(static_cast(result[i]), status); + if (U_FAILURE(status)) { + return NULL; + } + } } return fDecimalStr; } - -DigitList * -Formattable::getInternalDigitList() { - FmtStackData *stackData = (FmtStackData*)fStackData; - if(fDecimalNum != &(stackData->stackDecimalNum)) { - delete fDecimalNum; - fDecimalNum = new (&(stackData->stackDecimalNum), kOnStack) DigitList(); - } else { - fDecimalNum->clear(); - } - return fDecimalNum; -} - // --------------------------------------- void -Formattable::adoptDigitList(DigitList *dl) { - if(fDecimalNum==dl) { - fDecimalNum = NULL; // don't delete - } - dispose(); - - fDecimalNum = dl; - - if(dl==NULL) { // allow adoptDigitList(NULL) to clear - return; - } +Formattable::adoptDecimalQuantity(DecimalQuantity *dq) { + if (fDecimalQuantity != NULL) { + delete fDecimalQuantity; + } + fDecimalQuantity = dq; + if (dq == NULL) { // allow adoptDigitList(NULL) to clear + return; + } // Set the value into the Union of simple type values. // Cannot use the set() functions because they would delete the fDecimalNum value, - - if (fDecimalNum->fitsIntoLong(FALSE)) { + // TODO: fDecimalQuantity->fitsInInt() to kLong type. + /* + if (fDecimalQuantity->fitsIntoLong(FALSE)) { fType = kLong; fValue.fInt64 = fDecimalNum->getLong(); - } else if (fDecimalNum->fitsIntoInt64(FALSE)) { + } else + */ + if (fDecimalQuantity->fitsInLong()) { fType = kInt64; - fValue.fInt64 = fDecimalNum->getInt64(); + fValue.fInt64 = fDecimalQuantity->toLong(); } else { fType = kDouble; - fValue.fDouble = fDecimalNum->getDouble(); + fValue.fDouble = fDecimalQuantity->toDouble(); } } @@ -804,24 +794,12 @@ Formattable::setDecimalNumber(StringPiece numberString, UErrorCode &status) { } dispose(); - // Copy the input string and nul-terminate it. - // The decNumber library requires nul-terminated input. StringPiece input - // is not guaranteed nul-terminated. Too bad. - // CharString automatically adds the nul. - DigitList *dnum = new DigitList(); // TODO: use getInternalDigitList - if (dnum == NULL) { - status = U_MEMORY_ALLOCATION_ERROR; - return; - } - dnum->set(CharString(numberString, status).toStringPiece(), status); - if (U_FAILURE(status)) { - delete dnum; - return; // String didn't contain a decimal number. - } - adoptDigitList(dnum); + DecimalQuantity* dq = new DecimalQuantity(); + dq->setToDecNumber(numberString); + adoptDecimalQuantity(dq); // Note that we do not hang on to the caller's input string. - // If we are asked for the string, we will regenerate one from fDecimalNum. + // If we are asked for the string, we will regenerate one from fDecimalQuantity. } #if 0 diff --git a/icu4c/source/i18n/fmtableimp.h b/icu4c/source/i18n/fmtableimp.h index 12cea9a4409..2d18c6af7d2 100644 --- a/icu4c/source/i18n/fmtableimp.h +++ b/icu4c/source/i18n/fmtableimp.h @@ -10,7 +10,7 @@ #ifndef FMTABLEIMP_H #define FMTABLEIMP_H -#include "digitlst.h" +#include "number_decimalquantity.h" #if !UCONFIG_NO_FORMATTING @@ -20,7 +20,7 @@ U_NAMESPACE_BEGIN * @internal */ struct FmtStackData { - DigitList stackDecimalNum; // 128 + icu::number::impl::DecimalQuantity stackDecimalNum; // 128 //CharString stackDecimalStr; // 64 // ----- // 192 total diff --git a/icu4c/source/i18n/msgfmt.cpp b/icu4c/source/i18n/msgfmt.cpp index c2be3f7bd13..57faaa98211 100644 --- a/icu4c/source/i18n/msgfmt.cpp +++ b/icu4c/source/i18n/msgfmt.cpp @@ -49,6 +49,7 @@ #include "util.h" #include "uvector.h" #include "visibledigits.h" +#include "number_decimalquantity.h" // ***************************************************************************** // class MessageFormat @@ -1961,13 +1962,12 @@ UnicodeString MessageFormat::PluralSelectorProvider::select(void *ctx, double nu context.formatter->format(context.number, context.numberString, ec); auto* decFmt = dynamic_cast(context.formatter); if(decFmt != NULL) { - const IFixedDecimal& dec = decFmt->toNumberFormatter() - .formatDouble(context.number.getDouble(ec), ec) - .getFixedDecimal(ec); + number::impl::DecimalQuantity dq; + decFmt->formatToDecimalQuantity(number, dq, ec); if (U_FAILURE(ec)) { return UnicodeString(FALSE, OTHER_STRING, 5); } - return rules->select(dec); + return rules->select(dq); } else { return rules->select(number); } diff --git a/icu4c/source/i18n/nfsubs.cpp b/icu4c/source/i18n/nfsubs.cpp index 4c17aa28186..81aa2e5ffdc 100644 --- a/icu4c/source/i18n/nfsubs.cpp +++ b/icu4c/source/i18n/nfsubs.cpp @@ -19,8 +19,8 @@ #include "utypeinfo.h" // for 'typeid' to work #include "nfsubs.h" -#include "digitlst.h" #include "fmtableimp.h" +#include "number_decimalquantity.h" #if U_HAVE_RBNF @@ -47,6 +47,8 @@ static const UChar gGreaterGreaterThan[] = U_NAMESPACE_BEGIN +using number::impl::DecimalQuantity; + class SameValueSubstitution : public NFSubstitution { public: SameValueSubstitution(int32_t pos, @@ -1069,13 +1071,12 @@ FractionalPartSubstitution::doSubstitution(double number, UnicodeString& toInser // numberToFormat /= 10; // } - DigitList dl; - dl.set(number); - dl.roundFixedPoint(20); // round to 20 fraction digits. - dl.reduce(); // Removes any trailing zeros. + DecimalQuantity dl; + dl.setToDouble(number); + dl.roundToMagnitude(-20, UNUM_ROUND_HALFEVEN, status); // round to 20 fraction digits. UBool pad = FALSE; - for (int32_t didx = dl.getCount()-1; didx>=dl.getDecimalAt(); didx--) { + for (int32_t didx = dl.getLowerDisplayMagnitude(); didx<0; didx++) { // Loop iterates over fraction digits, starting with the LSD. // include both real digits from the number, and zeros // to the left of the MSD but to the right of the decimal point. @@ -1142,7 +1143,7 @@ FractionalPartSubstitution::doParse(const UnicodeString& text, int32_t digit; // double p10 = 0.1; - DigitList dl; + DecimalQuantity dl; NumberFormat* fmt = NULL; while (workText.length() > 0 && workPos.getIndex() != 0) { workPos.setIndex(0); @@ -1170,7 +1171,8 @@ FractionalPartSubstitution::doParse(const UnicodeString& text, } if (workPos.getIndex() != 0) { - dl.append((char)('0' + digit)); + // TODO(sffc): Make sure this is doing what it is supposed to do. + dl.appendDigit(static_cast(digit), 0, true); // result += digit * p10; // p10 /= 10; parsePosition.setIndex(parsePosition.getIndex() + workPos.getIndex()); @@ -1183,7 +1185,7 @@ FractionalPartSubstitution::doParse(const UnicodeString& text, } delete fmt; - result = dl.getCount() == 0 ? 0 : dl.getDouble(); + result = dl.toDouble(); result = composeRuleValue(result, baseValue); resVal.setDouble(result); return TRUE; diff --git a/icu4c/source/i18n/number_decimalquantity.h b/icu4c/source/i18n/number_decimalquantity.h index a104cc2d1ff..155fdfef597 100644 --- a/icu4c/source/i18n/number_decimalquantity.h +++ b/icu4c/source/i18n/number_decimalquantity.h @@ -241,6 +241,10 @@ class U_I18N_API DecimalQuantity : public IFixedDecimal, public UMemory { /** Visible for testing */ inline bool isExplicitExactDouble() { return explicitExactDouble; }; + bool operator==(const DecimalQuantity& other) const; + + bool operator!=(const DecimalQuantity& other) const; + /** * Bogus flag for when a DecimalQuantity is stored on the stack. */ diff --git a/icu4c/source/i18n/numfmt.cpp b/icu4c/source/i18n/numfmt.cpp index 8ed71a580e1..301b9855b11 100644 --- a/icu4c/source/i18n/numfmt.cpp +++ b/icu4c/source/i18n/numfmt.cpp @@ -51,10 +51,10 @@ #include "uassert.h" #include "umutex.h" #include "mutex.h" -#include "digitlst.h" #include #include "sharednumberformat.h" #include "unifiedcache.h" +#include "number_decimalquantity.h" //#define FMT_DEBUG @@ -524,7 +524,7 @@ ArgExtractor::ArgExtractor(const NumberFormat& /*nf*/, const Formattable& obj, U ArgExtractor::~ArgExtractor() { } -UnicodeString& NumberFormat::format(const DigitList &number, +UnicodeString& NumberFormat::format(const number::impl::DecimalQuantity &number, UnicodeString& appendTo, FieldPositionIterator* posIter, UErrorCode& status) const { @@ -534,7 +534,7 @@ UnicodeString& NumberFormat::format(const DigitList &number, if (U_FAILURE(status)) { return appendTo; } - double dnum = number.getDouble(); + double dnum = number.toDouble(); format(dnum, appendTo, posIter, status); return appendTo; } @@ -542,7 +542,7 @@ UnicodeString& NumberFormat::format(const DigitList &number, UnicodeString& -NumberFormat::format(const DigitList &number, +NumberFormat::format(const number::impl::DecimalQuantity &number, UnicodeString& appendTo, FieldPosition& pos, UErrorCode &status) const { @@ -552,7 +552,7 @@ NumberFormat::format(const DigitList &number, if (U_FAILURE(status)) { return appendTo; } - double dnum = number.getDouble(); + double dnum = number.toDouble(); format(dnum, appendTo, pos, status); return appendTo; } @@ -578,7 +578,7 @@ NumberFormat::format(const Formattable& obj, return cloneFmt->format(*n, appendTo, pos, status); } - if (n->isNumeric() && n->getDigitList() != NULL) { + if (n->isNumeric() && n->getDecimalQuantity() != NULL) { // Decimal Number. We will have a DigitList available if the value was // set to a decimal number, or if the value originated with a parse. // @@ -587,7 +587,7 @@ NumberFormat::format(const Formattable& obj, // know about DigitList to continue to operate as they had. // // DecimalFormat overrides the DigitList formatting functions. - format(*n->getDigitList(), appendTo, pos, status); + format(*n->getDecimalQuantity(), appendTo, pos, status); } else { switch (n->getType()) { case Formattable::kDouble: @@ -633,9 +633,9 @@ NumberFormat::format(const Formattable& obj, return cloneFmt->format(*n, appendTo, posIter, status); } - if (n->isNumeric() && n->getDigitList() != NULL) { + if (n->isNumeric() && n->getDecimalQuantity() != NULL) { // Decimal Number - format(*n->getDigitList(), appendTo, posIter, status); + format(*n->getDecimalQuantity(), appendTo, posIter, status); } else { switch (n->getType()) { case Formattable::kDouble: diff --git a/icu4c/source/i18n/plurrule.cpp b/icu4c/source/i18n/plurrule.cpp index 3da36d64b54..36d7bc7f981 100644 --- a/icu4c/source/i18n/plurrule.cpp +++ b/icu4c/source/i18n/plurrule.cpp @@ -22,7 +22,6 @@ #include "charstr.h" #include "cmemory.h" #include "cstring.h" -#include "digitlst.h" #include "hash.h" #include "locutil.h" #include "mutex.h" @@ -37,12 +36,14 @@ #include "unifiedcache.h" #include "digitinterval.h" #include "visibledigits.h" +#include "number_decimalquantity.h" #if !UCONFIG_NO_FORMATTING U_NAMESPACE_BEGIN using namespace icu::pluralimpl; +using icu::number::impl::DecimalQuantity; static const UChar PLURAL_KEYWORD_OTHER[]={LOW_O,LOW_T,LOW_H,LOW_E,LOW_R,0}; static const UChar PLURAL_DEFAULT_RULE[]={LOW_O,LOW_T,LOW_H,LOW_E,LOW_R,COLON,SPACE,LOW_N,0}; @@ -254,11 +255,10 @@ PluralRules::select(const Formattable& obj, const NumberFormat& fmt, UErrorCode& if (U_SUCCESS(status)) { const DecimalFormat *decFmt = dynamic_cast(&fmt); if (decFmt != NULL) { - const IFixedDecimal& dec = decFmt->toNumberFormatter() - .formatDouble(obj.getDouble(status), status) - .getFixedDecimal(status); + number::impl::DecimalQuantity dq; + decFmt->formatToDecimalQuantity(obj, dq, status); if (U_SUCCESS(status)) { - return select(dec); + return select(dq); } } else { double number = obj.getDouble(status); @@ -1477,14 +1477,14 @@ FixedDecimal::FixedDecimal() { FixedDecimal::FixedDecimal(const UnicodeString &num, UErrorCode &status) { CharString cs; cs.appendInvariantChars(num, status); - DigitList dl; - dl.set(cs.toStringPiece(), status); + DecimalQuantity dl; + dl.setToDecNumber(cs.toStringPiece()); if (U_FAILURE(status)) { init(0, 0, 0); return; } int32_t decimalPoint = num.indexOf(DOT); - double n = dl.getDouble(); + double n = dl.toDouble(); if (decimalPoint == -1) { init(n, 0, 0); } else { diff --git a/icu4c/source/i18n/plurrule_impl.h b/icu4c/source/i18n/plurrule_impl.h index 152c33e862d..a07fc23e035 100644 --- a/icu4c/source/i18n/plurrule_impl.h +++ b/icu4c/source/i18n/plurrule_impl.h @@ -248,6 +248,10 @@ class U_I18N_API IFixedDecimal { virtual bool isNaN() const = 0; virtual bool isInfinite() const = 0; + + virtual bool hasIntegerValue() { + return getPluralOperand(PLURAL_OPERAND_N) == getPluralOperand(PLURAL_OPERAND_I); + } }; /** diff --git a/icu4c/source/i18n/quantityformatter.cpp b/icu4c/source/i18n/quantityformatter.cpp index eaf92212755..9ef607e50a5 100644 --- a/icu4c/source/i18n/quantityformatter.cpp +++ b/icu4c/source/i18n/quantityformatter.cpp @@ -25,6 +25,7 @@ #include "standardplural.h" #include "visibledigits.h" #include "uassert.h" +#include "number_decimalquantity.h" U_NAMESPACE_BEGIN @@ -151,13 +152,12 @@ StandardPlural::Form QuantityFormatter::selectPlural( UnicodeString pluralKeyword; const DecimalFormat *decFmt = dynamic_cast(&fmt); if (decFmt != NULL) { - const IFixedDecimal& dec = decFmt->toNumberFormatter() - .formatDouble(number.getDouble(status), status) - .getFixedDecimal(status); + number::impl::DecimalQuantity dq; + decFmt->formatToDecimalQuantity(number, dq, status); if (U_FAILURE(status)) { return StandardPlural::OTHER; } - pluralKeyword = rules.select(dec); + pluralKeyword = rules.select(dq); decFmt->format(number, formattedNumber, pos, status); } else { if (number.getType() == Formattable::kDouble) { diff --git a/icu4c/source/i18n/rbnf.cpp b/icu4c/source/i18n/rbnf.cpp index 1b75e5ee1b7..3cc208585f6 100644 --- a/icu4c/source/i18n/rbnf.cpp +++ b/icu4c/source/i18n/rbnf.cpp @@ -34,7 +34,7 @@ #include "patternprops.h" #include "uresimp.h" #include "nfrs.h" -#include "digitlst.h" +#include "number_decimalquantity.h" // debugging // #define RBNF_DEBUG @@ -68,6 +68,8 @@ static const UChar gSemiPercent[] = U_NAMESPACE_BEGIN +using number::impl::DecimalQuantity; + UOBJECT_DEFINE_RTTI_IMPLEMENTATION(RuleBasedNumberFormat) /* @@ -1109,21 +1111,21 @@ RuleBasedNumberFormat::findRuleSet(const UnicodeString& name, UErrorCode& status } UnicodeString& -RuleBasedNumberFormat::format(const DigitList &number, +RuleBasedNumberFormat::format(const DecimalQuantity &number, UnicodeString &appendTo, FieldPositionIterator *posIter, UErrorCode &status) const { if (U_FAILURE(status)) { return appendTo; } - DigitList copy(number); - if (copy.fitsIntoInt64(false)) { - format(((DigitList &)number).getInt64(), appendTo, posIter, status); + DecimalQuantity copy(number); + if (copy.fitsInLong()) { + format(((DecimalQuantity &)number).toLong(), appendTo, posIter, status); } else { - copy.roundAtExponent(0); - if (copy.fitsIntoInt64(false)) { - format(number.getDouble(), appendTo, posIter, status); + copy.roundToMagnitude(0, number::impl::RoundingMode::UNUM_ROUND_HALFEVEN, status); + if (copy.fitsInLong()) { + format(number.toLong(), appendTo, posIter, status); } else { // We're outside of our normal range that this framework can handle. @@ -1132,7 +1134,7 @@ RuleBasedNumberFormat::format(const DigitList &number, // TODO this section should probably be optimized. The DecimalFormat is shared in ICU4J. NumberFormat *decimalFormat = NumberFormat::createInstance(locale, UNUM_DECIMAL, status); Formattable f; - f.adoptDigitList(new DigitList(number)); + f.adoptDecimalQuantity(new DecimalQuantity(number)); decimalFormat->format(f, appendTo, posIter, status); delete decimalFormat; } @@ -1142,21 +1144,21 @@ RuleBasedNumberFormat::format(const DigitList &number, UnicodeString& -RuleBasedNumberFormat::format(const DigitList &number, +RuleBasedNumberFormat::format(const DecimalQuantity &number, UnicodeString& appendTo, FieldPosition& pos, UErrorCode &status) const { if (U_FAILURE(status)) { return appendTo; } - DigitList copy(number); - if (copy.fitsIntoInt64(false)) { - format(((DigitList &)number).getInt64(), appendTo, pos, status); + DecimalQuantity copy(number); + if (copy.fitsInLong()) { + format(((DecimalQuantity &)number).toLong(), appendTo, pos, status); } else { - copy.roundAtExponent(0); - if (copy.fitsIntoInt64(false)) { - format(number.getDouble(), appendTo, pos, status); + copy.roundToMagnitude(0, number::impl::RoundingMode::UNUM_ROUND_HALFEVEN, status); + if (copy.fitsInLong()) { + format(number.toLong(), appendTo, pos, status); } else { // We're outside of our normal range that this framework can handle. @@ -1165,7 +1167,7 @@ RuleBasedNumberFormat::format(const DigitList &number, // TODO this section should probably be optimized. The DecimalFormat is shared in ICU4J. NumberFormat *decimalFormat = NumberFormat::createInstance(locale, UNUM_DECIMAL, status); Formattable f; - f.adoptDigitList(new DigitList(number)); + f.adoptDecimalQuantity(new DecimalQuantity(number)); decimalFormat->format(f, appendTo, pos, status); delete decimalFormat; } @@ -1270,11 +1272,13 @@ RuleBasedNumberFormat::format(double number, { int32_t startPos = toAppendTo.length(); if (getRoundingMode() != DecimalFormat::ERoundingMode::kRoundUnnecessary && !uprv_isNaN(number) && !uprv_isInfinite(number)) { - DigitList digitList; - digitList.set(number); - digitList.setRoundingMode(getRoundingMode()); - digitList.roundFixedPoint(getMaximumFractionDigits()); - number = digitList.getDouble(); + DecimalQuantity digitList; + digitList.setToDouble(number); + digitList.roundToMagnitude( + -getMaximumFractionDigits(), + static_cast(getRoundingMode()), + status); + number = digitList.toDouble(); } rs.format(number, toAppendTo, toAppendTo.length(), 0, status); adjustForCapitalizationContext(startPos, toAppendTo, status); @@ -1310,9 +1314,9 @@ RuleBasedNumberFormat::format(int64_t number, NFRuleSet *ruleSet, UnicodeString& NumberFormat *decimalFormat = NumberFormat::createInstance(locale, UNUM_DECIMAL, status); Formattable f; FieldPosition pos(FieldPosition::DONT_CARE); - DigitList *digitList = new DigitList(); - digitList->set(number); - f.adoptDigitList(digitList); + DecimalQuantity *digitList = new DecimalQuantity(); + digitList->setToLong(number); + f.adoptDecimalQuantity(digitList); decimalFormat->format(f, toAppendTo, pos, status); delete decimalFormat; } diff --git a/icu4c/source/i18n/unicode/compactdecimalformat.h b/icu4c/source/i18n/unicode/compactdecimalformat.h index 3fbe5da9cee..f5911176c8d 100644 --- a/icu4c/source/i18n/unicode/compactdecimalformat.h +++ b/icu4c/source/i18n/unicode/compactdecimalformat.h @@ -76,7 +76,7 @@ public: * Destructor. * @stable ICU 51 */ - virtual ~CompactDecimalFormat(); + ~CompactDecimalFormat() U_OVERRIDE; /** * Assignment operator. @@ -86,289 +86,8 @@ public: */ CompactDecimalFormat& operator=(const CompactDecimalFormat& rhs); - /** - * Clone this Format object polymorphically. The caller owns the - * result and should delete it when done. - * - * @return a polymorphic copy of this CompactDecimalFormat. - * @stable ICU 51 - */ - virtual Format* clone() const; - - /** - * Return TRUE if the given Format objects are semantically equal. - * Objects of different subclasses are considered unequal. - * - * @param other the object to be compared with. - * @return TRUE if the given Format objects are semantically equal. - * @stable ICU 51 - */ - virtual UBool operator==(const Format& other) const; - - using DecimalFormat::format; - /** - * Format a double or long number using base-10 representation. - * - * @param number The value to be formatted. - * @param appendTo Output parameter to receive result. - * Result is appended to existing contents. - * @param pos On input: an alignment field, if desired. - * On output: the offsets of the alignment field. - * @return Reference to 'appendTo' parameter. - * @stable ICU 51 - */ - virtual UnicodeString& format(double number, - UnicodeString& appendTo, - FieldPosition& pos) const; - - /** - * Format a double or long number using base-10 representation. - * - * @param number The value to be formatted. - * @param appendTo Output parameter to receive result. - * Result is appended to existing contents. - * @param pos On input: an alignment field, if desired. - * On output: the offsets of the alignment field. - * @param status - * @return Reference to 'appendTo' parameter. - * @internal - */ - virtual UnicodeString& format(double number, - UnicodeString& appendTo, - FieldPosition& pos, - UErrorCode &status) const; - - /** - * Format a double or long number using base-10 representation. - * Currently sets status to U_UNSUPPORTED_ERROR. - * - * @param number The value to be formatted. - * @param appendTo Output parameter to receive result. - * Result is appended to existing contents. - * @param posIter On return, can be used to iterate over positions - * of fields generated by this format call. - * Can be NULL. - * @param status Output param filled with success/failure status. - * @return Reference to 'appendTo' parameter. - * @internal - */ - virtual UnicodeString& format(double number, - UnicodeString& appendTo, - FieldPositionIterator* posIter, - UErrorCode& status) const; - - /** - * Format a long number using base-10 representation. - * - * @param number The value to be formatted. - * @param appendTo Output parameter to receive result. - * Result is appended to existing contents. - * @param pos On input: an alignment field, if desired. - * On output: the offsets of the alignment field. - * @return Reference to 'appendTo' parameter. - * @stable ICU 56 - */ - virtual UnicodeString& format(int32_t number, - UnicodeString& appendTo, - FieldPosition& pos) const; - - /** - * Format a long number using base-10 representation. - * - * @param number The value to be formatted. - * @param appendTo Output parameter to receive result. - * Result is appended to existing contents. - * @param pos On input: an alignment field, if desired. - * On output: the offsets of the alignment field. - * @return Reference to 'appendTo' parameter. - * @internal - */ - virtual UnicodeString& format(int32_t number, - UnicodeString& appendTo, - FieldPosition& pos, - UErrorCode &status) const; - - /** - * Format a long number using base-10 representation. - * Currently sets status to U_UNSUPPORTED_ERROR - * - * @param number The value to be formatted. - * @param appendTo Output parameter to receive result. - * Result is appended to existing contents. - * @param posIter On return, can be used to iterate over positions - * of fields generated by this format call. - * Can be NULL. - * @param status Output param filled with success/failure status. - * @return Reference to 'appendTo' parameter. - * @internal - */ - virtual UnicodeString& format(int32_t number, - UnicodeString& appendTo, - FieldPositionIterator* posIter, - UErrorCode& status) const; - - /** - * Format an int64 number using base-10 representation. - * - * @param number The value to be formatted. - * @param appendTo Output parameter to receive result. - * Result is appended to existing contents. - * @param pos On input: an alignment field, if desired. - * On output: the offsets of the alignment field. - * @return Reference to 'appendTo' parameter. - * @stable ICU 51 - */ - virtual UnicodeString& format(int64_t number, - UnicodeString& appendTo, - FieldPosition& pos) const; - - /** - * Format an int64 number using base-10 representation. - * - * @param number The value to be formatted. - * @param appendTo Output parameter to receive result. - * Result is appended to existing contents. - * @param pos On input: an alignment field, if desired. - * On output: the offsets of the alignment field. - * @return Reference to 'appendTo' parameter. - * @internal - */ - virtual UnicodeString& format(int64_t number, - UnicodeString& appendTo, - FieldPosition& pos, - UErrorCode &status) const; - - /** - * Format an int64 number using base-10 representation. - * Currently sets status to U_UNSUPPORTED_ERROR - * - * @param number The value to be formatted. - * @param appendTo Output parameter to receive result. - * Result is appended to existing contents. - * @param posIter On return, can be used to iterate over positions - * of fields generated by this format call. - * Can be NULL. - * @param status Output param filled with success/failure status. - * @return Reference to 'appendTo' parameter. - * @internal - */ - virtual UnicodeString& format(int64_t number, - UnicodeString& appendTo, - FieldPositionIterator* posIter, - UErrorCode& status) const; - - /** - * Format a decimal number. Currently sets status to U_UNSUPPORTED_ERROR - * The syntax of the unformatted number is a "numeric string" - * as defined in the Decimal Arithmetic Specification, available at - * http://speleotrove.com/decimal - * - * @param number The unformatted number, as a string. - * @param appendTo Output parameter to receive result. - * Result is appended to existing contents. - * @param posIter On return, can be used to iterate over positions - * of fields generated by this format call. - * Can be NULL. - * @param status Output param filled with success/failure status. - * @return Reference to 'appendTo' parameter. - * @internal - */ - virtual UnicodeString& format(StringPiece number, - UnicodeString& appendTo, - FieldPositionIterator* posIter, - UErrorCode& status) const; - - /** - * Format a decimal number. Currently sets status to U_UNSUPPORTED_ERROR - * The number is a DigitList wrapper onto a floating point decimal number. - * The default implementation in NumberFormat converts the decimal number - * to a double and formats that. - * - * @param number The number, a DigitList format Decimal Floating Point. - * @param appendTo Output parameter to receive result. - * Result is appended to existing contents. - * @param posIter On return, can be used to iterate over positions - * of fields generated by this format call. - * @param status Output param filled with success/failure status. - * @return Reference to 'appendTo' parameter. - * @internal - */ - virtual UnicodeString& format(const DigitList &number, - UnicodeString& appendTo, - FieldPositionIterator* posIter, - UErrorCode& status) const; - - /** - * Format a decimal number. Currently sets status to U_UNSUPPORTED_ERROR. - * The number is a DigitList wrapper onto a floating point decimal number. - * The default implementation in NumberFormat converts the decimal number - * to a double and formats that. - * - * @param number The number, a DigitList format Decimal Floating Point. - * @param appendTo Output parameter to receive result. - * Result is appended to existing contents. - * @param pos On input: an alignment field, if desired. - * On output: the offsets of the alignment field. - * @param status Output param filled with success/failure status. - * @return Reference to 'appendTo' parameter. - * @internal - */ - virtual UnicodeString& format(const DigitList &number, - UnicodeString& appendTo, - FieldPosition& pos, - UErrorCode& status) const; - - /** - * CompactDecimalFormat does not support parsing. This implementation - * does nothing. - * @param text Unused. - * @param result Does not change. - * @param parsePosition Does not change. - * @see Formattable - * @stable ICU 51 - */ - virtual void parse(const UnicodeString& text, - Formattable& result, - ParsePosition& parsePosition) const; - - /** - * CompactDecimalFormat does not support parsing. This implementation - * sets status to U_UNSUPPORTED_ERROR - * - * @param text Unused. - * @param result Does not change. - * @param status Always set to U_UNSUPPORTED_ERROR. - * @stable ICU 51 - */ - virtual void parse(const UnicodeString& text, - Formattable& result, - UErrorCode& status) const; - - /** - * Parses text from the given string as a currency amount. Unlike - * the parse() method, this method will attempt to parse a generic - * currency name, searching for a match of this object's locale's - * currency display names, or for a 3-letter ISO currency code. - * This method will fail if this format is not a currency format, - * that is, if it does not contain the currency pattern symbol - * (U+00A4) in its prefix or suffix. This implementation always returns - * NULL. - * - * @param text the string to parse - * @param pos input-output position; on input, the position within text - * to match; must have 0 <= pos.getIndex() < text.length(); - * on output, the position after the last matched character. - * If the parse fails, the position in unchanged upon output. - * @return if parse succeeds, a pointer to a newly-created CurrencyAmount - * object (owned by the caller) containing information about - * the parsed currency; if parse fails, this is NULL. - * @internal - */ - virtual CurrencyAmount* parseCurrency(const UnicodeString& text, - ParsePosition& pos) const; - /** * Return the class ID for this class. This is useful only for * comparing to a return value from getDynamicClassID(). For example: @@ -394,17 +113,6 @@ public: * @stable ICU 51 */ virtual UClassID getDynamicClassID() const; - -private: - - const UHashtable* _unitsByVariant; - const double* _divisors; - PluralRules* _pluralRules; - - // Default constructor not implemented. - CompactDecimalFormat(const DecimalFormat &, const UHashtable* unitsByVariant, const double* divisors, PluralRules* pluralRules); - - UBool eqHelper(const CompactDecimalFormat& that) const; }; U_NAMESPACE_END diff --git a/icu4c/source/i18n/unicode/decimfmt.h b/icu4c/source/i18n/unicode/decimfmt.h index dbd01a347d9..1fe5d99d32e 100644 --- a/icu4c/source/i18n/unicode/decimfmt.h +++ b/icu4c/source/i18n/unicode/decimfmt.h @@ -67,6 +67,12 @@ class DecimalFormatImpl; class PluralRules; class VisibleDigitsWithExponent; +namespace number { +namespace impl { +class DecimalQuantity; +} +} + // explicit template instantiation. see digitlst.h // (When building DLLs for Windows this is required.) #if U_PF_WINDOWS <= U_PLATFORM && U_PLATFORM <= U_PF_CYGWIN @@ -1084,11 +1090,11 @@ public: /** * Format a decimal number. - * The number is a DigitList wrapper onto a floating point decimal number. + * The number is a DecimalQuantity wrapper onto a floating point decimal number. * The default implementation in NumberFormat converts the decimal number * to a double and formats that. * - * @param number The number, a DigitList format Decimal Floating Point. + * @param number The number, a DecimalQuantity format Decimal Floating Point. * @param appendTo Output parameter to receive result. * Result is appended to existing contents. * @param posIter On return, can be used to iterate over positions @@ -1097,50 +1103,18 @@ public: * @return Reference to 'appendTo' parameter. * @internal */ - UnicodeString& format(const DigitList &number, + UnicodeString& format(const number::impl::DecimalQuantity &number, UnicodeString& appendTo, FieldPositionIterator* posIter, UErrorCode& status) const U_OVERRIDE; /** * Format a decimal number. - * @param number The number - * @param appendTo Output parameter to receive result. - * Result is appended to existing contents. - * @param pos On input: an alignment field, if desired. - * On output: the offsets of the alignment field. - * @param status Output param filled with success/failure status. - * @return Reference to 'appendTo' parameter. - * @internal - */ - virtual UnicodeString& format(const VisibleDigitsWithExponent &number, - UnicodeString& appendTo, - FieldPosition& pos, - UErrorCode& status) const; - - /** - * Format a decimal number. - * @param number The number - * @param appendTo Output parameter to receive result. - * Result is appended to existing contents. - * @param posIter On return, can be used to iterate over positions - * of fields generated by this format call. - * @param status Output param filled with success/failure status. - * @return Reference to 'appendTo' parameter. - * @internal - */ - virtual UnicodeString& format(const VisibleDigitsWithExponent &number, - UnicodeString& appendTo, - FieldPositionIterator* posIter, - UErrorCode& status) const; - - /** - * Format a decimal number. - * The number is a DigitList wrapper onto a floating point decimal number. + * The number is a DecimalQuantity wrapper onto a floating point decimal number. * The default implementation in NumberFormat converts the decimal number * to a double and formats that. * - * @param number The number, a DigitList format Decimal Floating Point. + * @param number The number, a DecimalQuantity format Decimal Floating Point. * @param appendTo Output parameter to receive result. * Result is appended to existing contents. * @param pos On input: an alignment field, if desired. @@ -1149,7 +1123,7 @@ public: * @return Reference to 'appendTo' parameter. * @internal */ - UnicodeString& format(const DigitList &number, + UnicodeString& format(const number::impl::DecimalQuantity &number, UnicodeString& appendTo, FieldPosition& pos, UErrorCode& status) const U_OVERRIDE; @@ -1967,6 +1941,25 @@ public: */ UCurrencyUsage getCurrencyUsage() const; +#ifndef U_HIDE_INTERNAL_API + /** + * Format a number and save it into the given DecimalQuantity. + * Internal, not intended for public use. + * @internal + */ + void formatToDecimalQuantity(double number, number::impl::DecimalQuantity& output, + UErrorCode& status) const; + + /** + * Get a DecimalQuantity corresponding to a formattable as it would be + * formatted by this DecimalFormat. + * Internal, not intended for public use. + * @internal + */ + void formatToDecimalQuantity(const Formattable& number, number::impl::DecimalQuantity& output, + UErrorCode& status) const; +#endif + /** * Converts this DecimalFormat to a NumberFormatter. Starting in ICU 60, * NumberFormatter is the recommended way to format numbers. diff --git a/icu4c/source/i18n/unicode/fmtable.h b/icu4c/source/i18n/unicode/fmtable.h index 766a71969de..67278039110 100644 --- a/icu4c/source/i18n/unicode/fmtable.h +++ b/icu4c/source/i18n/unicode/fmtable.h @@ -33,7 +33,11 @@ U_NAMESPACE_BEGIN class CharString; -class DigitList; +namespace number { +namespace impl { +class DecimalQuantity; +} +} /** * \def UNUM_INTERNAL_STACKARRAY_SIZE @@ -649,24 +653,19 @@ public: * Internal function, do not use. * TODO: figure out how to make this be non-public. * NumberFormat::format(Formattable, ... - * needs to get at the DigitList, if it exists, for + * needs to get at the DecimalQuantity, if it exists, for * big decimal formatting. * @internal */ - DigitList *getDigitList() const { return fDecimalNum;} + number::impl::DecimalQuantity *getDecimalQuantity() const { return fDecimalQuantity;} /** - * @internal - */ - DigitList *getInternalDigitList(); - - /** - * Adopt, and set value from, a DigitList + * Adopt, and set value from, a DecimalQuantity * Internal Function, do not use. - * @param dl the Digit List to be adopted + * @param dl the DecimalQuantity to be adopted * @internal */ - void adoptDigitList(DigitList *dl); + void adoptDecimalQuantity(number::impl::DecimalQuantity *dq); /** * Internal function to return the CharString pointer. @@ -706,9 +705,7 @@ private: CharString *fDecimalStr; - DigitList *fDecimalNum; - - char fStackData[UNUM_INTERNAL_STACKARRAY_SIZE]; // must be big enough for DigitList + number::impl::DecimalQuantity *fDecimalQuantity; Type fType; UnicodeString fBogus; // Bogus string when it's needed. diff --git a/icu4c/source/i18n/unicode/numfmt.h b/icu4c/source/i18n/unicode/numfmt.h index 4a8e049f931..8184812ef70 100644 --- a/icu4c/source/i18n/unicode/numfmt.h +++ b/icu4c/source/i18n/unicode/numfmt.h @@ -558,13 +558,13 @@ public: public: /** * Format a decimal number. - * The number is a DigitList wrapper onto a floating point decimal number. + * The number is a DecimalQuantity wrapper onto a floating point decimal number. * The default implementation in NumberFormat converts the decimal number * to a double and formats that. Subclasses of NumberFormat that want * to specifically handle big decimal numbers must override this method. * class DecimalFormat does so. * - * @param number The number, a DigitList format Decimal Floating Point. + * @param number The number, a DecimalQuantity format Decimal Floating Point. * @param appendTo Output parameter to receive result. * Result is appended to existing contents. * @param posIter On return, can be used to iterate over positions @@ -573,20 +573,20 @@ public: * @return Reference to 'appendTo' parameter. * @internal */ - virtual UnicodeString& format(const DigitList &number, + virtual UnicodeString& format(const number::impl::DecimalQuantity &number, UnicodeString& appendTo, FieldPositionIterator* posIter, UErrorCode& status) const; /** * Format a decimal number. - * The number is a DigitList wrapper onto a floating point decimal number. + * The number is a DecimalQuantity wrapper onto a floating point decimal number. * The default implementation in NumberFormat converts the decimal number * to a double and formats that. Subclasses of NumberFormat that want * to specifically handle big decimal numbers must override this method. * class DecimalFormat does so. * - * @param number The number, a DigitList format Decimal Floating Point. + * @param number The number, a DecimalQuantity format Decimal Floating Point. * @param appendTo Output parameter to receive result. * Result is appended to existing contents. * @param pos On input: an alignment field, if desired. @@ -595,7 +595,7 @@ public: * @return Reference to 'appendTo' parameter. * @internal */ - virtual UnicodeString& format(const DigitList &number, + virtual UnicodeString& format(const number::impl::DecimalQuantity &number, UnicodeString& appendTo, FieldPosition& pos, UErrorCode& status) const; diff --git a/icu4c/source/i18n/unicode/rbnf.h b/icu4c/source/i18n/unicode/rbnf.h index 12925443b2d..ab5a019de30 100644 --- a/icu4c/source/i18n/unicode/rbnf.h +++ b/icu4c/source/i18n/unicode/rbnf.h @@ -884,7 +884,7 @@ protected: * @return Reference to 'appendTo' parameter. * @internal */ - virtual UnicodeString& format(const DigitList &number, + virtual UnicodeString& format(const number::impl::DecimalQuantity &number, UnicodeString& appendTo, FieldPositionIterator* posIter, UErrorCode& status) const; @@ -906,7 +906,7 @@ protected: * @return Reference to 'appendTo' parameter. * @internal */ - virtual UnicodeString& format(const DigitList &number, + virtual UnicodeString& format(const number::impl::DecimalQuantity &number, UnicodeString& appendTo, FieldPosition& pos, UErrorCode& status) const; diff --git a/icu4c/source/test/intltest/dcfmapts.cpp b/icu4c/source/test/intltest/dcfmapts.cpp index b4639f73a45..cf854de4068 100644 --- a/icu4c/source/test/intltest/dcfmapts.cpp +++ b/icu4c/source/test/intltest/dcfmapts.cpp @@ -23,6 +23,7 @@ #include "putilimp.h" #include "plurrule_impl.h" #include +#include // This is an API test, not a unit test. It doesn't test very many cases, and doesn't // try to test the full functionality. It just calls each function in the class and @@ -613,171 +614,172 @@ void IntlTestDecimalFormatAPI::TestFixedDecimal() { if (status == U_MISSING_RESOURCE_ERROR) { return; } - FixedDecimal fd = df->getFixedDecimal(44, status); + number::impl::DecimalQuantity fd; + df->formatToDecimalQuantity(44, fd, status); TEST_ASSERT_STATUS(status); - ASSERT_EQUAL(44, fd.source); - ASSERT_EQUAL(0, fd.visibleDecimalDigitCount); - ASSERT_EQUAL(FALSE, fd.isNegative); + ASSERT_EQUAL(44, fd.getPluralOperand(PLURAL_OPERAND_N)); + ASSERT_EQUAL(0, fd.getPluralOperand(PLURAL_OPERAND_V)); + ASSERT_EQUAL(FALSE, fd.isNegative()); - fd = df->getFixedDecimal(-44, status); + df->formatToDecimalQuantity(-44, fd, status); TEST_ASSERT_STATUS(status); - ASSERT_EQUAL(44, fd.source); - ASSERT_EQUAL(0, fd.visibleDecimalDigitCount); - ASSERT_EQUAL(TRUE, fd.isNegative); + ASSERT_EQUAL(44, fd.getPluralOperand(PLURAL_OPERAND_N)); + ASSERT_EQUAL(0, fd.getPluralOperand(PLURAL_OPERAND_V)); + ASSERT_EQUAL(TRUE, fd.isNegative()); df.adoptInsteadAndCheckErrorCode(new DecimalFormat("###.00##", status), status); TEST_ASSERT_STATUS(status); - fd = df->getFixedDecimal(123.456, status); + df->formatToDecimalQuantity(123.456, fd, status); TEST_ASSERT_STATUS(status); - ASSERT_EQUAL(3, fd.visibleDecimalDigitCount); // v - ASSERT_EQUAL(456, fd.decimalDigits); // f - ASSERT_EQUAL(456, fd.decimalDigitsWithoutTrailingZeros); // t - ASSERT_EQUAL(123, fd.intValue); // i - ASSERT_EQUAL(123.456, fd.source); // n - ASSERT_EQUAL(FALSE, fd.hasIntegerValue); - ASSERT_EQUAL(FALSE, fd.isNegative); + ASSERT_EQUAL(3, fd.getPluralOperand(PLURAL_OPERAND_V)); // v + ASSERT_EQUAL(456, fd.getPluralOperand(PLURAL_OPERAND_F)); // f + ASSERT_EQUAL(456, fd.getPluralOperand(PLURAL_OPERAND_T)); // t + ASSERT_EQUAL(123, fd.getPluralOperand(PLURAL_OPERAND_I)); // i + ASSERT_EQUAL(123.456, fd.getPluralOperand(PLURAL_OPERAND_N)); // n + ASSERT_EQUAL(FALSE, fd.hasIntegerValue()); + ASSERT_EQUAL(FALSE, fd.isNegative()); - fd = df->getFixedDecimal(-123.456, status); + df->formatToDecimalQuantity(-123.456, fd, status); TEST_ASSERT_STATUS(status); - ASSERT_EQUAL(3, fd.visibleDecimalDigitCount); // v - ASSERT_EQUAL(456, fd.decimalDigits); // f - ASSERT_EQUAL(456, fd.decimalDigitsWithoutTrailingZeros); // t - ASSERT_EQUAL(123, fd.intValue); // i - ASSERT_EQUAL(123.456, fd.source); // n - ASSERT_EQUAL(FALSE, fd.hasIntegerValue); - ASSERT_EQUAL(TRUE, fd.isNegative); + ASSERT_EQUAL(3, fd.getPluralOperand(PLURAL_OPERAND_V)); // v + ASSERT_EQUAL(456, fd.getPluralOperand(PLURAL_OPERAND_F)); // f + ASSERT_EQUAL(456, fd.getPluralOperand(PLURAL_OPERAND_T)); // t + ASSERT_EQUAL(123, fd.getPluralOperand(PLURAL_OPERAND_I)); // i + ASSERT_EQUAL(123.456, fd.getPluralOperand(PLURAL_OPERAND_N)); // n + ASSERT_EQUAL(FALSE, fd.hasIntegerValue()); + ASSERT_EQUAL(TRUE, fd.isNegative()); // test max int digits df->setMaximumIntegerDigits(2); - fd = df->getFixedDecimal(123.456, status); + df->formatToDecimalQuantity(123.456, fd, status); TEST_ASSERT_STATUS(status); - ASSERT_EQUAL(3, fd.visibleDecimalDigitCount); // v - ASSERT_EQUAL(456, fd.decimalDigits); // f - ASSERT_EQUAL(456, fd.decimalDigitsWithoutTrailingZeros); // t - ASSERT_EQUAL(23, fd.intValue); // i - ASSERT_EQUAL(23.456, fd.source); // n - ASSERT_EQUAL(FALSE, fd.hasIntegerValue); - ASSERT_EQUAL(FALSE, fd.isNegative); + ASSERT_EQUAL(3, fd.getPluralOperand(PLURAL_OPERAND_V)); // v + ASSERT_EQUAL(456, fd.getPluralOperand(PLURAL_OPERAND_F)); // f + ASSERT_EQUAL(456, fd.getPluralOperand(PLURAL_OPERAND_T)); // t + ASSERT_EQUAL(23, fd.getPluralOperand(PLURAL_OPERAND_I)); // i + ASSERT_EQUAL(23.456, fd.getPluralOperand(PLURAL_OPERAND_N)); // n + ASSERT_EQUAL(FALSE, fd.hasIntegerValue()); + ASSERT_EQUAL(FALSE, fd.isNegative()); - fd = df->getFixedDecimal(-123.456, status); + df->formatToDecimalQuantity(-123.456, fd, status); TEST_ASSERT_STATUS(status); - ASSERT_EQUAL(3, fd.visibleDecimalDigitCount); // v - ASSERT_EQUAL(456, fd.decimalDigits); // f - ASSERT_EQUAL(456, fd.decimalDigitsWithoutTrailingZeros); // t - ASSERT_EQUAL(23, fd.intValue); // i - ASSERT_EQUAL(23.456, fd.source); // n - ASSERT_EQUAL(FALSE, fd.hasIntegerValue); - ASSERT_EQUAL(TRUE, fd.isNegative); + ASSERT_EQUAL(3, fd.getPluralOperand(PLURAL_OPERAND_V)); // v + ASSERT_EQUAL(456, fd.getPluralOperand(PLURAL_OPERAND_F)); // f + ASSERT_EQUAL(456, fd.getPluralOperand(PLURAL_OPERAND_T)); // t + ASSERT_EQUAL(23, fd.getPluralOperand(PLURAL_OPERAND_I)); // i + ASSERT_EQUAL(23.456, fd.getPluralOperand(PLURAL_OPERAND_N)); // n + ASSERT_EQUAL(FALSE, fd.hasIntegerValue()); + ASSERT_EQUAL(TRUE, fd.isNegative()); // test max fraction digits df->setMaximumIntegerDigits(2000000000); df->setMaximumFractionDigits(2); - fd = df->getFixedDecimal(123.456, status); + df->formatToDecimalQuantity(123.456, fd, status); TEST_ASSERT_STATUS(status); - ASSERT_EQUAL(2, fd.visibleDecimalDigitCount); // v - ASSERT_EQUAL(46, fd.decimalDigits); // f - ASSERT_EQUAL(46, fd.decimalDigitsWithoutTrailingZeros); // t - ASSERT_EQUAL(123, fd.intValue); // i - ASSERT_EQUAL(123.46, fd.source); // n - ASSERT_EQUAL(FALSE, fd.hasIntegerValue); - ASSERT_EQUAL(FALSE, fd.isNegative); + ASSERT_EQUAL(2, fd.getPluralOperand(PLURAL_OPERAND_V)); // v + ASSERT_EQUAL(46, fd.getPluralOperand(PLURAL_OPERAND_F)); // f + ASSERT_EQUAL(46, fd.getPluralOperand(PLURAL_OPERAND_T)); // t + ASSERT_EQUAL(123, fd.getPluralOperand(PLURAL_OPERAND_I)); // i + ASSERT_EQUAL(123.46, fd.getPluralOperand(PLURAL_OPERAND_N)); // n + ASSERT_EQUAL(FALSE, fd.hasIntegerValue()); + ASSERT_EQUAL(FALSE, fd.isNegative()); - fd = df->getFixedDecimal(-123.456, status); + df->formatToDecimalQuantity(-123.456, fd, status); TEST_ASSERT_STATUS(status); - ASSERT_EQUAL(2, fd.visibleDecimalDigitCount); // v - ASSERT_EQUAL(46, fd.decimalDigits); // f - ASSERT_EQUAL(46, fd.decimalDigitsWithoutTrailingZeros); // t - ASSERT_EQUAL(123, fd.intValue); // i - ASSERT_EQUAL(123.46, fd.source); // n - ASSERT_EQUAL(FALSE, fd.hasIntegerValue); - ASSERT_EQUAL(TRUE, fd.isNegative); + ASSERT_EQUAL(2, fd.getPluralOperand(PLURAL_OPERAND_V)); // v + ASSERT_EQUAL(46, fd.getPluralOperand(PLURAL_OPERAND_F)); // f + ASSERT_EQUAL(46, fd.getPluralOperand(PLURAL_OPERAND_T)); // t + ASSERT_EQUAL(123, fd.getPluralOperand(PLURAL_OPERAND_I)); // i + ASSERT_EQUAL(123.46, fd.getPluralOperand(PLURAL_OPERAND_N)); // n + ASSERT_EQUAL(FALSE, fd.hasIntegerValue()); + ASSERT_EQUAL(TRUE, fd.isNegative()); // test esoteric rounding df->setMaximumFractionDigits(6); df->setRoundingIncrement(7.3); - fd = df->getFixedDecimal(30.0, status); + df->formatToDecimalQuantity(30.0, fd, status); TEST_ASSERT_STATUS(status); - ASSERT_EQUAL(2, fd.visibleDecimalDigitCount); // v - ASSERT_EQUAL(20, fd.decimalDigits); // f - ASSERT_EQUAL(2, fd.decimalDigitsWithoutTrailingZeros); // t - ASSERT_EQUAL(29, fd.intValue); // i - ASSERT_EQUAL(29.2, fd.source); // n - ASSERT_EQUAL(FALSE, fd.hasIntegerValue); - ASSERT_EQUAL(FALSE, fd.isNegative); + ASSERT_EQUAL(2, fd.getPluralOperand(PLURAL_OPERAND_V)); // v + ASSERT_EQUAL(20, fd.getPluralOperand(PLURAL_OPERAND_F)); // f + ASSERT_EQUAL(2, fd.getPluralOperand(PLURAL_OPERAND_T)); // t + ASSERT_EQUAL(29, fd.getPluralOperand(PLURAL_OPERAND_I)); // i + ASSERT_EQUAL(29.2, fd.getPluralOperand(PLURAL_OPERAND_N)); // n + ASSERT_EQUAL(FALSE, fd.hasIntegerValue()); + ASSERT_EQUAL(FALSE, fd.isNegative()); - fd = df->getFixedDecimal(-30.0, status); + df->formatToDecimalQuantity(-30.0, fd, status); TEST_ASSERT_STATUS(status); - ASSERT_EQUAL(2, fd.visibleDecimalDigitCount); // v - ASSERT_EQUAL(20, fd.decimalDigits); // f - ASSERT_EQUAL(2, fd.decimalDigitsWithoutTrailingZeros); // t - ASSERT_EQUAL(29, fd.intValue); // i - ASSERT_EQUAL(29.2, fd.source); // n - ASSERT_EQUAL(FALSE, fd.hasIntegerValue); - ASSERT_EQUAL(TRUE, fd.isNegative); + ASSERT_EQUAL(2, fd.getPluralOperand(PLURAL_OPERAND_V)); // v + ASSERT_EQUAL(20, fd.getPluralOperand(PLURAL_OPERAND_F)); // f + ASSERT_EQUAL(2, fd.getPluralOperand(PLURAL_OPERAND_T)); // t + ASSERT_EQUAL(29, fd.getPluralOperand(PLURAL_OPERAND_I)); // i + ASSERT_EQUAL(29.2, fd.getPluralOperand(PLURAL_OPERAND_N)); // n + ASSERT_EQUAL(FALSE, fd.hasIntegerValue()); + ASSERT_EQUAL(TRUE, fd.isNegative()); df.adoptInsteadAndCheckErrorCode(new DecimalFormat("###", status), status); TEST_ASSERT_STATUS(status); - fd = df->getFixedDecimal(123.456, status); + df->formatToDecimalQuantity(123.456, fd, status); TEST_ASSERT_STATUS(status); - ASSERT_EQUAL(0, fd.visibleDecimalDigitCount); - ASSERT_EQUAL(0, fd.decimalDigits); - ASSERT_EQUAL(0, fd.decimalDigitsWithoutTrailingZeros); - ASSERT_EQUAL(123, fd.intValue); - ASSERT_EQUAL(TRUE, fd.hasIntegerValue); - ASSERT_EQUAL(FALSE, fd.isNegative); + ASSERT_EQUAL(0, fd.getPluralOperand(PLURAL_OPERAND_V)); + ASSERT_EQUAL(0, fd.getPluralOperand(PLURAL_OPERAND_F)); + ASSERT_EQUAL(0, fd.getPluralOperand(PLURAL_OPERAND_T)); + ASSERT_EQUAL(123, fd.getPluralOperand(PLURAL_OPERAND_I)); + ASSERT_EQUAL(TRUE, fd.hasIntegerValue()); + ASSERT_EQUAL(FALSE, fd.isNegative()); df.adoptInsteadAndCheckErrorCode(new DecimalFormat("###.0", status), status); TEST_ASSERT_STATUS(status); - fd = df->getFixedDecimal(123.01, status); + df->formatToDecimalQuantity(123.01, fd, status); TEST_ASSERT_STATUS(status); - ASSERT_EQUAL(1, fd.visibleDecimalDigitCount); - ASSERT_EQUAL(0, fd.decimalDigits); - ASSERT_EQUAL(0, fd.decimalDigitsWithoutTrailingZeros); - ASSERT_EQUAL(123, fd.intValue); - ASSERT_EQUAL(TRUE, fd.hasIntegerValue); - ASSERT_EQUAL(FALSE, fd.isNegative); + ASSERT_EQUAL(1, fd.getPluralOperand(PLURAL_OPERAND_V)); + ASSERT_EQUAL(0, fd.getPluralOperand(PLURAL_OPERAND_F)); + ASSERT_EQUAL(0, fd.getPluralOperand(PLURAL_OPERAND_T)); + ASSERT_EQUAL(123, fd.getPluralOperand(PLURAL_OPERAND_I)); + ASSERT_EQUAL(TRUE, fd.hasIntegerValue()); + ASSERT_EQUAL(FALSE, fd.isNegative()); df.adoptInsteadAndCheckErrorCode(new DecimalFormat("###.0", status), status); TEST_ASSERT_STATUS(status); - fd = df->getFixedDecimal(123.06, status); + df->formatToDecimalQuantity(123.06, fd, status); TEST_ASSERT_STATUS(status); - ASSERT_EQUAL(1, fd.visibleDecimalDigitCount); - ASSERT_EQUAL(1, fd.decimalDigits); - ASSERT_EQUAL(1, fd.decimalDigitsWithoutTrailingZeros); - ASSERT_EQUAL(123, fd.intValue); - ASSERT_EQUAL(FALSE, fd.hasIntegerValue); - ASSERT_EQUAL(FALSE, fd.isNegative); + ASSERT_EQUAL(1, fd.getPluralOperand(PLURAL_OPERAND_V)); + ASSERT_EQUAL(1, fd.getPluralOperand(PLURAL_OPERAND_F)); + ASSERT_EQUAL(1, fd.getPluralOperand(PLURAL_OPERAND_T)); + ASSERT_EQUAL(123, fd.getPluralOperand(PLURAL_OPERAND_I)); + ASSERT_EQUAL(FALSE, fd.hasIntegerValue()); + ASSERT_EQUAL(FALSE, fd.isNegative()); df.adoptInsteadAndCheckErrorCode(new DecimalFormat("@@@@@", status), status); // Significant Digits TEST_ASSERT_STATUS(status); - fd = df->getFixedDecimal(123, status); + df->formatToDecimalQuantity(123, fd, status); TEST_ASSERT_STATUS(status); - ASSERT_EQUAL(2, fd.visibleDecimalDigitCount); - ASSERT_EQUAL(0, fd.decimalDigits); - ASSERT_EQUAL(0, fd.decimalDigitsWithoutTrailingZeros); - ASSERT_EQUAL(123, fd.intValue); - ASSERT_EQUAL(TRUE, fd.hasIntegerValue); - ASSERT_EQUAL(FALSE, fd.isNegative); + ASSERT_EQUAL(2, fd.getPluralOperand(PLURAL_OPERAND_V)); + ASSERT_EQUAL(0, fd.getPluralOperand(PLURAL_OPERAND_F)); + ASSERT_EQUAL(0, fd.getPluralOperand(PLURAL_OPERAND_T)); + ASSERT_EQUAL(123, fd.getPluralOperand(PLURAL_OPERAND_I)); + ASSERT_EQUAL(TRUE, fd.hasIntegerValue()); + ASSERT_EQUAL(FALSE, fd.isNegative()); df.adoptInsteadAndCheckErrorCode(new DecimalFormat("@@@@@", status), status); // Significant Digits TEST_ASSERT_STATUS(status); - fd = df->getFixedDecimal(1.23, status); + df->formatToDecimalQuantity(1.23, fd, status); TEST_ASSERT_STATUS(status); - ASSERT_EQUAL(4, fd.visibleDecimalDigitCount); - ASSERT_EQUAL(2300, fd.decimalDigits); - ASSERT_EQUAL(23, fd.decimalDigitsWithoutTrailingZeros); - ASSERT_EQUAL(1, fd.intValue); - ASSERT_EQUAL(FALSE, fd.hasIntegerValue); - ASSERT_EQUAL(FALSE, fd.isNegative); + ASSERT_EQUAL(4, fd.getPluralOperand(PLURAL_OPERAND_V)); + ASSERT_EQUAL(2300, fd.getPluralOperand(PLURAL_OPERAND_F)); + ASSERT_EQUAL(23, fd.getPluralOperand(PLURAL_OPERAND_T)); + ASSERT_EQUAL(1, fd.getPluralOperand(PLURAL_OPERAND_I)); + ASSERT_EQUAL(FALSE, fd.hasIntegerValue()); + ASSERT_EQUAL(FALSE, fd.isNegative()); - fd = df->getFixedDecimal(uprv_getInfinity(), status); + df->formatToDecimalQuantity(uprv_getInfinity(), fd, status); TEST_ASSERT_STATUS(status); - ASSERT_EQUAL(TRUE, fd.isNanOrInfinity()); - fd = df->getFixedDecimal(0.0, status); - ASSERT_EQUAL(FALSE, fd.isNanOrInfinity()); - fd = df->getFixedDecimal(uprv_getNaN(), status); - ASSERT_EQUAL(TRUE, fd.isNanOrInfinity()); + ASSERT_EQUAL(TRUE, fd.isNaN() || fd.isInfinite()); + df->formatToDecimalQuantity(0.0, fd, status); + ASSERT_EQUAL(FALSE, fd.isNaN() || fd.isInfinite()); + df->formatToDecimalQuantity(uprv_getNaN(), fd, status); + ASSERT_EQUAL(TRUE, fd.isNaN() || fd.isInfinite()); TEST_ASSERT_STATUS(status); // Test Big Decimal input. @@ -788,135 +790,141 @@ void IntlTestDecimalFormatAPI::TestFixedDecimal() { TEST_ASSERT_STATUS(status); Formattable fable("12.34", status); TEST_ASSERT_STATUS(status); - fd = df->getFixedDecimal(fable, status); + df->formatToDecimalQuantity(fable, fd, status); TEST_ASSERT_STATUS(status); - ASSERT_EQUAL(2, fd.visibleDecimalDigitCount); - ASSERT_EQUAL(34, fd.decimalDigits); - ASSERT_EQUAL(34, fd.decimalDigitsWithoutTrailingZeros); - ASSERT_EQUAL(12, fd.intValue); - ASSERT_EQUAL(FALSE, fd.hasIntegerValue); - ASSERT_EQUAL(FALSE, fd.isNegative); + ASSERT_EQUAL(2, fd.getPluralOperand(PLURAL_OPERAND_V)); + ASSERT_EQUAL(34, fd.getPluralOperand(PLURAL_OPERAND_F)); + ASSERT_EQUAL(34, fd.getPluralOperand(PLURAL_OPERAND_T)); + ASSERT_EQUAL(12, fd.getPluralOperand(PLURAL_OPERAND_I)); + ASSERT_EQUAL(FALSE, fd.hasIntegerValue()); + ASSERT_EQUAL(FALSE, fd.isNegative()); fable.setDecimalNumber("12.345678901234567890123456789", status); TEST_ASSERT_STATUS(status); - fd = df->getFixedDecimal(fable, status); + df->formatToDecimalQuantity(fable, fd, status); TEST_ASSERT_STATUS(status); - ASSERT_EQUAL(22, fd.visibleDecimalDigitCount); - ASSERT_EQUAL(345678901234567890LL, fd.decimalDigits); - ASSERT_EQUAL(34567890123456789LL, fd.decimalDigitsWithoutTrailingZeros); - ASSERT_EQUAL(12, fd.intValue); - ASSERT_EQUAL(FALSE, fd.hasIntegerValue); - ASSERT_EQUAL(FALSE, fd.isNegative); + ASSERT_EQUAL(22, fd.getPluralOperand(PLURAL_OPERAND_V)); + ASSERT_EQUAL(345678901234567890LL, fd.getPluralOperand(PLURAL_OPERAND_F)); + ASSERT_EQUAL(34567890123456789LL, fd.getPluralOperand(PLURAL_OPERAND_T)); + ASSERT_EQUAL(12, fd.getPluralOperand(PLURAL_OPERAND_I)); + ASSERT_EQUAL(FALSE, fd.hasIntegerValue()); + ASSERT_EQUAL(FALSE, fd.isNegative()); // On field overflow, Integer part is truncated on the left, fraction part on the right. fable.setDecimalNumber("123456789012345678901234567890.123456789012345678901234567890", status); TEST_ASSERT_STATUS(status); - fd = df->getFixedDecimal(fable, status); + df->formatToDecimalQuantity(fable, fd, status); TEST_ASSERT_STATUS(status); - ASSERT_EQUAL(22, fd.visibleDecimalDigitCount); - ASSERT_EQUAL(123456789012345678LL, fd.decimalDigits); - ASSERT_EQUAL(123456789012345678LL, fd.decimalDigitsWithoutTrailingZeros); - ASSERT_EQUAL(345678901234567890LL, fd.intValue); - ASSERT_EQUAL(FALSE, fd.hasIntegerValue); - ASSERT_EQUAL(FALSE, fd.isNegative); + ASSERT_EQUAL(22, fd.getPluralOperand(PLURAL_OPERAND_V)); + ASSERT_EQUAL(123456789012345678LL, fd.getPluralOperand(PLURAL_OPERAND_F)); + ASSERT_EQUAL(123456789012345678LL, fd.getPluralOperand(PLURAL_OPERAND_T)); + ASSERT_EQUAL(345678901234567890LL, fd.getPluralOperand(PLURAL_OPERAND_I)); + ASSERT_EQUAL(FALSE, fd.hasIntegerValue()); + ASSERT_EQUAL(FALSE, fd.isNegative()); // Digits way to the right of the decimal but within the format's precision aren't truncated fable.setDecimalNumber("1.0000000000000000000012", status); TEST_ASSERT_STATUS(status); - fd = df->getFixedDecimal(fable, status); + df->formatToDecimalQuantity(fable, fd, status); TEST_ASSERT_STATUS(status); - ASSERT_EQUAL(22, fd.visibleDecimalDigitCount); - ASSERT_EQUAL(12, fd.decimalDigits); - ASSERT_EQUAL(12, fd.decimalDigitsWithoutTrailingZeros); - ASSERT_EQUAL(1, fd.intValue); - ASSERT_EQUAL(FALSE, fd.hasIntegerValue); - ASSERT_EQUAL(FALSE, fd.isNegative); + ASSERT_EQUAL(22, fd.getPluralOperand(PLURAL_OPERAND_V)); + ASSERT_EQUAL(12, fd.getPluralOperand(PLURAL_OPERAND_F)); + ASSERT_EQUAL(12, fd.getPluralOperand(PLURAL_OPERAND_T)); + ASSERT_EQUAL(1, fd.getPluralOperand(PLURAL_OPERAND_I)); + ASSERT_EQUAL(FALSE, fd.hasIntegerValue()); + ASSERT_EQUAL(FALSE, fd.isNegative()); // Digits beyond the precision of the format are rounded away fable.setDecimalNumber("1.000000000000000000000012", status); TEST_ASSERT_STATUS(status); - fd = df->getFixedDecimal(fable, status); + df->formatToDecimalQuantity(fable, fd, status); TEST_ASSERT_STATUS(status); - ASSERT_EQUAL(2, fd.visibleDecimalDigitCount); - ASSERT_EQUAL(0, fd.decimalDigits); - ASSERT_EQUAL(0, fd.decimalDigitsWithoutTrailingZeros); - ASSERT_EQUAL(1, fd.intValue); - ASSERT_EQUAL(TRUE, fd.hasIntegerValue); - ASSERT_EQUAL(FALSE, fd.isNegative); + ASSERT_EQUAL(2, fd.getPluralOperand(PLURAL_OPERAND_V)); + ASSERT_EQUAL(0, fd.getPluralOperand(PLURAL_OPERAND_F)); + ASSERT_EQUAL(0, fd.getPluralOperand(PLURAL_OPERAND_T)); + ASSERT_EQUAL(1, fd.getPluralOperand(PLURAL_OPERAND_I)); + ASSERT_EQUAL(TRUE, fd.hasIntegerValue()); + ASSERT_EQUAL(FALSE, fd.isNegative()); // Negative numbers come through fable.setDecimalNumber("-1.0000000000000000000012", status); TEST_ASSERT_STATUS(status); - fd = df->getFixedDecimal(fable, status); + df->formatToDecimalQuantity(fable, fd, status); TEST_ASSERT_STATUS(status); - ASSERT_EQUAL(22, fd.visibleDecimalDigitCount); - ASSERT_EQUAL(12, fd.decimalDigits); - ASSERT_EQUAL(12, fd.decimalDigitsWithoutTrailingZeros); - ASSERT_EQUAL(1, fd.intValue); - ASSERT_EQUAL(FALSE, fd.hasIntegerValue); - ASSERT_EQUAL(TRUE, fd.isNegative); + ASSERT_EQUAL(22, fd.getPluralOperand(PLURAL_OPERAND_V)); + ASSERT_EQUAL(12, fd.getPluralOperand(PLURAL_OPERAND_F)); + ASSERT_EQUAL(12, fd.getPluralOperand(PLURAL_OPERAND_T)); + ASSERT_EQUAL(1, fd.getPluralOperand(PLURAL_OPERAND_I)); + ASSERT_EQUAL(FALSE, fd.hasIntegerValue()); + ASSERT_EQUAL(TRUE, fd.isNegative()); // MinFractionDigits from format larger than from number. fable.setDecimalNumber("1000000000000000000000.3", status); TEST_ASSERT_STATUS(status); - fd = df->getFixedDecimal(fable, status); + df->formatToDecimalQuantity(fable, fd, status); TEST_ASSERT_STATUS(status); - ASSERT_EQUAL(2, fd.visibleDecimalDigitCount); - ASSERT_EQUAL(30, fd.decimalDigits); - ASSERT_EQUAL(3, fd.decimalDigitsWithoutTrailingZeros); - ASSERT_EQUAL(100000000000000000LL, fd.intValue); - ASSERT_EQUAL(FALSE, fd.hasIntegerValue); - ASSERT_EQUAL(FALSE, fd.isNegative); + ASSERT_EQUAL(2, fd.getPluralOperand(PLURAL_OPERAND_V)); + ASSERT_EQUAL(30, fd.getPluralOperand(PLURAL_OPERAND_F)); + ASSERT_EQUAL(3, fd.getPluralOperand(PLURAL_OPERAND_T)); + ASSERT_EQUAL(100000000000000000LL, fd.getPluralOperand(PLURAL_OPERAND_I)); + ASSERT_EQUAL(FALSE, fd.hasIntegerValue()); + ASSERT_EQUAL(FALSE, fd.isNegative()); fable.setDecimalNumber("1000000000000000050000.3", status); TEST_ASSERT_STATUS(status); - fd = df->getFixedDecimal(fable, status); + df->formatToDecimalQuantity(fable, fd, status); TEST_ASSERT_STATUS(status); - ASSERT_EQUAL(2, fd.visibleDecimalDigitCount); - ASSERT_EQUAL(30, fd.decimalDigits); - ASSERT_EQUAL(3, fd.decimalDigitsWithoutTrailingZeros); - ASSERT_EQUAL(50000LL, fd.intValue); - ASSERT_EQUAL(FALSE, fd.hasIntegerValue); - ASSERT_EQUAL(FALSE, fd.isNegative); + ASSERT_EQUAL(2, fd.getPluralOperand(PLURAL_OPERAND_V)); + ASSERT_EQUAL(30, fd.getPluralOperand(PLURAL_OPERAND_F)); + ASSERT_EQUAL(3, fd.getPluralOperand(PLURAL_OPERAND_T)); + ASSERT_EQUAL(50000LL, fd.getPluralOperand(PLURAL_OPERAND_I)); + ASSERT_EQUAL(FALSE, fd.hasIntegerValue()); + ASSERT_EQUAL(FALSE, fd.isNegative()); // Test some int64_t values that are out of the range of a double fable.setInt64(4503599627370496LL); TEST_ASSERT_STATUS(status); - fd = df->getFixedDecimal(fable, status); + df->formatToDecimalQuantity(fable, fd, status); TEST_ASSERT_STATUS(status); - ASSERT_EQUAL(2, fd.visibleDecimalDigitCount); - ASSERT_EQUAL(0, fd.decimalDigits); - ASSERT_EQUAL(0, fd.decimalDigitsWithoutTrailingZeros); - ASSERT_EQUAL(4503599627370496LL, fd.intValue); - ASSERT_EQUAL(TRUE, fd.hasIntegerValue); - ASSERT_EQUAL(FALSE, fd.isNegative); + ASSERT_EQUAL(2, fd.getPluralOperand(PLURAL_OPERAND_V)); + ASSERT_EQUAL(0, fd.getPluralOperand(PLURAL_OPERAND_F)); + ASSERT_EQUAL(0, fd.getPluralOperand(PLURAL_OPERAND_T)); + ASSERT_EQUAL(4503599627370496LL, fd.getPluralOperand(PLURAL_OPERAND_I)); + ASSERT_EQUAL(TRUE, fd.hasIntegerValue()); + ASSERT_EQUAL(FALSE, fd.isNegative()); fable.setInt64(4503599627370497LL); TEST_ASSERT_STATUS(status); - fd = df->getFixedDecimal(fable, status); + df->formatToDecimalQuantity(fable, fd, status); TEST_ASSERT_STATUS(status); - ASSERT_EQUAL(2, fd.visibleDecimalDigitCount); - ASSERT_EQUAL(0, fd.decimalDigits); - ASSERT_EQUAL(0, fd.decimalDigitsWithoutTrailingZeros); - ASSERT_EQUAL(4503599627370497LL, fd.intValue); - ASSERT_EQUAL(TRUE, fd.hasIntegerValue); - ASSERT_EQUAL(FALSE, fd.isNegative); + ASSERT_EQUAL(2, fd.getPluralOperand(PLURAL_OPERAND_V)); + ASSERT_EQUAL(0, fd.getPluralOperand(PLURAL_OPERAND_F)); + ASSERT_EQUAL(0, fd.getPluralOperand(PLURAL_OPERAND_T)); + ASSERT_EQUAL(4503599627370497LL, fd.getPluralOperand(PLURAL_OPERAND_I)); + ASSERT_EQUAL(TRUE, fd.hasIntegerValue()); + ASSERT_EQUAL(FALSE, fd.isNegative()); fable.setInt64(9223372036854775807LL); TEST_ASSERT_STATUS(status); - fd = df->getFixedDecimal(fable, status); + df->formatToDecimalQuantity(fable, fd, status); TEST_ASSERT_STATUS(status); - ASSERT_EQUAL(2, fd.visibleDecimalDigitCount); - ASSERT_EQUAL(0, fd.decimalDigits); - ASSERT_EQUAL(0, fd.decimalDigitsWithoutTrailingZeros); + ASSERT_EQUAL(2, fd.getPluralOperand(PLURAL_OPERAND_V)); + ASSERT_EQUAL(0, fd.getPluralOperand(PLURAL_OPERAND_F)); + ASSERT_EQUAL(0, fd.getPluralOperand(PLURAL_OPERAND_T)); // note: going through DigitList path to FixedDecimal, which is trimming // int64_t fields to 18 digits. See ticket Ticket #10374 - // ASSERT_EQUAL(223372036854775807LL, fd.intValue); - if (!(fd.intValue == 223372036854775807LL || fd.intValue == 9223372036854775807LL)) { - dataerrln("File %s, Line %d, fd.intValue = %lld", __FILE__, __LINE__, fd.intValue); + // ASSERT_EQUAL(223372036854775807LL, fd.getPluralOperand(PLURAL_OPERAND_I); + if (!( + fd.getPluralOperand(PLURAL_OPERAND_I) == 223372036854775807LL || + fd.getPluralOperand(PLURAL_OPERAND_I) == 9223372036854775807LL)) { + dataerrln( + "File %s, Line %d, fd.getPluralOperand(PLURAL_OPERAND_I = %lld", + __FILE__, + __LINE__, + fd.getPluralOperand(PLURAL_OPERAND_I)); } - ASSERT_EQUAL(TRUE, fd.hasIntegerValue); - ASSERT_EQUAL(FALSE, fd.isNegative); + ASSERT_EQUAL(TRUE, fd.hasIntegerValue()); + ASSERT_EQUAL(FALSE, fd.isNegative()); } diff --git a/icu4c/source/test/intltest/numberformattesttuple.cpp b/icu4c/source/test/intltest/numberformattesttuple.cpp index 496aaeccde2..d862d068cd2 100644 --- a/icu4c/source/test/intltest/numberformattesttuple.cpp +++ b/icu4c/source/test/intltest/numberformattesttuple.cpp @@ -15,7 +15,6 @@ #include "charstr.h" #include "cstring.h" #include "cmemory.h" -#include "digitlst.h" static NumberFormatTestTuple *gNullPtr = NULL; diff --git a/icu4c/source/test/intltest/numfmtst.cpp b/icu4c/source/test/intltest/numfmtst.cpp index a72567903f5..a257e12f8b4 100644 --- a/icu4c/source/test/intltest/numfmtst.cpp +++ b/icu4c/source/test/intltest/numfmtst.cpp @@ -23,7 +23,6 @@ #include "unicode/measfmt.h" #include "unicode/curramt.h" #include "unicode/strenum.h" -#include "digitlst.h" #include "textfile.h" #include "tokiter.h" #include "charstr.h" @@ -40,6 +39,7 @@ #include "numberformattesttuple.h" #include "datadrivennumberformattestsuite.h" #include "unicode/msgfmt.h" +#include "number_decimalquantity.h" #if (U_PLATFORM == U_PF_AIX) || (U_PLATFORM == U_PF_OS390) // These should not be macros. If they are, @@ -62,6 +62,7 @@ namespace std { #endif #endif +using icu::number::impl::DecimalQuantity; class NumberFormatTestDataDriven : public DataDrivenNumberFormatTestSuite { protected: @@ -83,34 +84,34 @@ UBool isParseCurrencyPass( UErrorCode &status); }; -static DigitList &strToDigitList( +static DecimalQuantity &strToDigitList( const UnicodeString &str, - DigitList &digitList, + DecimalQuantity &digitList, UErrorCode &status) { if (U_FAILURE(status)) { return digitList; } if (str == "NaN") { - digitList.set(uprv_getNaN()); + digitList.setToDouble(uprv_getNaN()); return digitList; } if (str == "-Inf") { - digitList.set(-1*uprv_getInfinity()); + digitList.setToDouble(-1*uprv_getInfinity()); return digitList; } if (str == "Inf") { - digitList.set(uprv_getInfinity()); + digitList.setToDouble(uprv_getInfinity()); return digitList; } CharString formatValue; formatValue.appendInvariantChars(str, status); - digitList.set(StringPiece(formatValue.data()), status, 0); + digitList.setToDecNumber(StringPiece(formatValue.data())); return digitList; } static UnicodeString &format( const DecimalFormat &fmt, - const DigitList &digitList, + const DecimalQuantity &digitList, UnicodeString &appendTo, UErrorCode &status) { if (U_FAILURE(status)) { @@ -315,7 +316,7 @@ UBool NumberFormatTestDataDriven::isFormatPass( if (appendErrorMessage.length() > 0) { return FALSE; } - DigitList digitList; + DecimalQuantity digitList; strToDigitList(tuple.format, digitList, status); { UnicodeString appendTo; @@ -330,7 +331,7 @@ UBool NumberFormatTestDataDriven::isFormatPass( return FALSE; } } - double doubleVal = digitList.getDouble(); + double doubleVal = digitList.toDouble(); { UnicodeString appendTo; format(*fmtPtr, doubleVal, appendTo, status); @@ -345,7 +346,7 @@ UBool NumberFormatTestDataDriven::isFormatPass( } } if (!uprv_isNaN(doubleVal) && !uprv_isInfinite(doubleVal) && doubleVal == uprv_floor(doubleVal)) { - int64_t intVal = digitList.getInt64(); + int64_t intVal = digitList.toLong(); { UnicodeString appendTo; format(*fmtPtr, intVal, appendTo, status); @@ -446,13 +447,13 @@ UBool NumberFormatTestDataDriven::isParsePass( } return TRUE; } - DigitList expected; + DecimalQuantity expected; strToDigitList(tuple.output, expected, status); if (U_FAILURE(status)) { appendErrorMessage.append("Error parsing."); return FALSE; } - if (expected != *result.getDigitList()) { + if (expected != *result.getDecimalQuantity()) { appendErrorMessage.append(UnicodeString("Expected: ") + tuple.output + ", but got: " + resultStr + " (" + ppos.getIndex() + ":" + ppos.getErrorIndex() + ")"); return FALSE; } @@ -490,13 +491,13 @@ UBool NumberFormatTestDataDriven::isParseCurrencyPass( appendErrorMessage.append(UnicodeString("Parse succeeded: ") + resultStr + ", but was expected to fail."); return TRUE; // TRUE because failure handling is in the test suite } - DigitList expected; + DecimalQuantity expected; strToDigitList(tuple.output, expected, status); if (U_FAILURE(status)) { appendErrorMessage.append("Error parsing."); return FALSE; } - if (expected != *currAmt->getNumber().getDigitList()) { + if (expected != *currAmt->getNumber().getDecimalQuantity()) { appendErrorMessage.append(UnicodeString("Expected: ") + tuple.output + ", but got: " + resultStr + " (" + ppos.getIndex() + ":" + ppos.getErrorIndex() + ")"); return FALSE; } @@ -7024,9 +7025,9 @@ void NumberFormatTest::TestDecimal() { dataerrln("Unable to create NumberFormat"); } else { UnicodeString formattedResult; - DigitList dl; + DecimalQuantity dl; StringPiece num("123.4566666666666666666666666666666666621E+40"); - dl.set(num, status); + dl.setToDecNumber(num); ASSERT_SUCCESS(status); fmtr->format(dl, formattedResult, NULL, status); ASSERT_SUCCESS(status); @@ -7034,7 +7035,7 @@ void NumberFormatTest::TestDecimal() { status = U_ZERO_ERROR; num.set("666.666"); - dl.set(num, status); + dl.setToDecNumber(num); FieldPosition pos(NumberFormat::FRACTION_FIELD); ASSERT_SUCCESS(status); formattedResult.remove(); @@ -8671,14 +8672,6 @@ void NumberFormatTest::Test11868() { } } -void NumberFormatTest::Test10727_RoundingZero() { - DigitList d; - d.set(-0.0); - assertFalse("", d.isPositive()); - d.round(3); - assertFalse("", d.isPositive()); -} - void NumberFormatTest::Test11376_getAndSetPositivePrefix() { { const UChar USD[] = {0x55, 0x53, 0x44, 0x0}; diff --git a/icu4c/source/test/intltest/plurults.cpp b/icu4c/source/test/intltest/plurults.cpp index 7d342287d98..57221263039 100644 --- a/icu4c/source/test/intltest/plurults.cpp +++ b/icu4c/source/test/intltest/plurults.cpp @@ -24,10 +24,12 @@ #include "unicode/stringpiece.h" #include "cmemory.h" -#include "digitlst.h" #include "plurrule_impl.h" #include "plurults.h" #include "uhash.h" +#include "number_decimalquantity.h" + +using icu::number::impl::DecimalQuantity; void setupResult(const int32_t testSource[], char result[], int32_t* max); UBool checkEqual(const PluralRules &test, char *result, int32_t max); @@ -633,14 +635,14 @@ void PluralRulesTest::checkSelect(const LocalPointer &rules, UError } // DigitList is a convenient way to parse the decimal number string and get a double. - DigitList dl; - dl.set(StringPiece(num), status); + DecimalQuantity dl; + dl.setToDecNumber(StringPiece(num)); if (U_FAILURE(status)) { errln("file %s, line %d, ICU error status: %s.", __FILE__, line, u_errorName(status)); status = U_ZERO_ERROR; continue; } - double numDbl = dl.getDouble(); + double numDbl = dl.toDouble(); const char *decimalPoint = strchr(num, '.'); int fractionDigitCount = decimalPoint == NULL ? 0 : (num + strlen(num) - 1) - decimalPoint; int fractionDigits = fractionDigitCount == 0 ? 0 : atoi(decimalPoint + 1); diff --git a/icu4c/source/test/intltest/uobjtest.cpp b/icu4c/source/test/intltest/uobjtest.cpp index d58e8c25d33..d55ba7e5a13 100644 --- a/icu4c/source/test/intltest/uobjtest.cpp +++ b/icu4c/source/test/intltest/uobjtest.cpp @@ -215,7 +215,6 @@ UObject *UObjectTest::testClassNoClassID(UObject *obj, const char *className, co #include "rbt_data.h" #include "nultrans.h" #include "anytrans.h" -#include "digitlst.h" #include "esctrn.h" #include "funcrepl.h" #include "servnotf.h"