From 1f1a485c3c564c21e6b26dff1ae58d86cbfb38f5 Mon Sep 17 00:00:00 2001 From: Shane Carr Date: Wed, 13 Sep 2017 07:49:26 +0000 Subject: [PATCH] ICU-13177 Adding IFixedDecimal interface to C++. X-SVN-Rev: 40391 --- icu4c/source/i18n/decimfmtimpl.cpp | 3 +- icu4c/source/i18n/plurrule.cpp | 51 +++++++----- icu4c/source/i18n/plurrule_impl.h | 101 ++++++++++++++++++++++-- icu4c/source/i18n/unicode/plurrule.h | 4 +- icu4c/source/test/intltest/dcfmapts.cpp | 6 +- 5 files changed, 135 insertions(+), 30 deletions(-) diff --git a/icu4c/source/i18n/decimfmtimpl.cpp b/icu4c/source/i18n/decimfmtimpl.cpp index b1f00325da2..62bd956fa5b 100644 --- a/icu4c/source/i18n/decimfmtimpl.cpp +++ b/icu4c/source/i18n/decimfmtimpl.cpp @@ -521,7 +521,8 @@ static FixedDecimal &initFixedDecimal( const VisibleDigits &digits, FixedDecimal &result) { result.source = 0.0; result.isNegative = digits.isNegative(); - result.isNanOrInfinity = digits.isNaNOrInfinity(); + result._isNaN = digits.isNaN(); + result._isInfinite = digits.isInfinite(); digits.getFixedDecimal( result.source, result.intValue, result.decimalDigits, result.decimalDigitsWithoutTrailingZeros, diff --git a/icu4c/source/i18n/plurrule.cpp b/icu4c/source/i18n/plurrule.cpp index 013d3fcac35..950243e42e2 100644 --- a/icu4c/source/i18n/plurrule.cpp +++ b/icu4c/source/i18n/plurrule.cpp @@ -268,7 +268,7 @@ PluralRules::select(const Formattable& obj, const NumberFormat& fmt, UErrorCode& } UnicodeString -PluralRules::select(const FixedDecimal &number) const { +PluralRules::select(const IFixedDecimal &number) const { if (mRules == NULL) { return UnicodeString(TRUE, PLURAL_DEFAULT_RULE, -1); } @@ -783,15 +783,15 @@ AndConstraint::~AndConstraint() { UBool -AndConstraint::isFulfilled(const FixedDecimal &number) { +AndConstraint::isFulfilled(const IFixedDecimal &number) { UBool result = TRUE; if (digitsType == none) { // An empty AndConstraint, created by a rule with a keyword but no following expression. return TRUE; } - double n = number.get(digitsType); // pulls n | i | v | f value for the number. - // Will always be positive. - // May be non-integer (n option only) + double n = number.getPluralOperand(digitsType); // pulls n | i | v | f value for the number. + // Will always be positive. + // May be non-integer (n option only) do { if (integerOnly && n != uprv_floor(n)) { result = FALSE; @@ -873,7 +873,7 @@ OrConstraint::add() } UBool -OrConstraint::isFulfilled(const FixedDecimal &number) { +OrConstraint::isFulfilled(const IFixedDecimal &number) { OrConstraint* orRule=this; UBool result=FALSE; @@ -914,8 +914,8 @@ RuleChain::~RuleChain() { UnicodeString -RuleChain::select(const FixedDecimal &number) const { - if (!number.isNanOrInfinity) { +RuleChain::select(const IFixedDecimal &number) const { + if (!number.isNaN() && !number.isInfinite()) { for (const RuleChain *rules = this; rules != NULL; rules = rules->fNext) { if (rules->ruleHeader->isFulfilled(number)) { return rules->fKeyword; @@ -1411,7 +1411,8 @@ FixedDecimal::FixedDecimal(const VisibleDigits &digits) { decimalDigitsWithoutTrailingZeros, visibleDecimalDigitCount, hasIntegerValue); isNegative = digits.isNegative(); - isNanOrInfinity = digits.isNaNOrInfinity(); + _isNaN = digits.isNaN(); + _isInfinite = digits.isInfinite(); } FixedDecimal::FixedDecimal(double n, int32_t v, int64_t f) { @@ -1476,7 +1477,8 @@ FixedDecimal::FixedDecimal(const FixedDecimal &other) { intValue = other.intValue; hasIntegerValue = other.hasIntegerValue; isNegative = other.isNegative; - isNanOrInfinity = other.isNanOrInfinity; + _isNaN = other._isNaN; + _isInfinite = other._isInfinite; } @@ -1489,8 +1491,9 @@ void FixedDecimal::init(double n) { void FixedDecimal::init(double n, int32_t v, int64_t f) { isNegative = n < 0.0; source = fabs(n); - isNanOrInfinity = uprv_isNaN(source) || uprv_isPositiveInfinity(source); - if (isNanOrInfinity) { + _isNaN = uprv_isNaN(source); + _isInfinite = uprv_isInfinite(source); + if (_isNaN || _isInfinite) { v = 0; f = 0; intValue = 0; @@ -1610,19 +1613,31 @@ void FixedDecimal::adjustForMinFractionDigits(int32_t minFractionDigits) { } -double FixedDecimal::get(tokenType operand) const { +double FixedDecimal::getPluralOperand(PluralOperand operand) const { switch(operand) { - case tVariableN: return source; - case tVariableI: return (double)intValue; - case tVariableF: return (double)decimalDigits; - case tVariableT: return (double)decimalDigitsWithoutTrailingZeros; - case tVariableV: return visibleDecimalDigitCount; + case PLURAL_OPERAND_N: return source; + case PLURAL_OPERAND_I: return intValue; + case PLURAL_OPERAND_F: return decimalDigits; + case PLURAL_OPERAND_T: return decimalDigitsWithoutTrailingZeros; + case PLURAL_OPERAND_V: return visibleDecimalDigitCount; default: U_ASSERT(FALSE); // unexpected. return source; } } +bool FixedDecimal::isNaN() const { + return _isNaN; +} + +bool FixedDecimal::isInfinite() const { + return _isInfinite; +} + +bool FixedDecimal::isNanOrInfinity() const { + return _isNaN || _isInfinite; +} + int32_t FixedDecimal::getVisibleFractionDigitCount() const { return visibleDecimalDigitCount; } diff --git a/icu4c/source/i18n/plurrule_impl.h b/icu4c/source/i18n/plurrule_impl.h index 9f5f66c1b74..a7e2654febf 100644 --- a/icu4c/source/i18n/plurrule_impl.h +++ b/icu4c/source/i18n/plurrule_impl.h @@ -28,6 +28,7 @@ #include "unicode/ures.h" #include "uvector.h" #include "hash.h" +#include "uassert.h" class PluralRulesTest; @@ -177,6 +178,87 @@ private: }; +enum PluralOperand { + /** + * The double value of the entire number. + */ + PLURAL_OPERAND_N, + + /** + * The integer value, with the fraction digits truncated off. + */ + PLURAL_OPERAND_I, + + /** + * All visible fraction digits as an integer, including trailing zeros. + */ + PLURAL_OPERAND_F, + + /** + * Visible fraction digits as an integer, not including trailing zeros. + */ + PLURAL_OPERAND_T, + + /** + * Number of visible fraction digits. + */ + PLURAL_OPERAND_V, + + /** + * Number of visible fraction digits, not including trailing zeros. + */ + PLURAL_OPERAND_W, + + /** + * THIS OPERAND IS DEPRECATED AND HAS BEEN REMOVED FROM THE SPEC. + * + *

Returns the integer value, but will fail if the number has fraction digits. + * That is, using "j" instead of "i" is like implicitly adding "v is 0". + * + *

For example, "j is 3" is equivalent to "i is 3 and v is 0": it matches + * "3" but not "3.1" or "3.0". + */ + PLURAL_OPERAND_J +}; + +/** + * An interface to FixedDecimal, allowing for other implementations. + * @internal + */ +class IFixedDecimal { + public: + virtual ~IFixedDecimal() = default; + + /** + * Returns the value corresponding to the specified operand (n, i, f, t, v, or w). + * If the operand is 'n', returns a double; otherwise, returns an integer. + */ + virtual double getPluralOperand(PluralOperand operand) const = 0; + + /** Converts from the tokenType enum to PluralOperand. */ + virtual double getPluralOperand(tokenType tt) const { + switch(tt) { + case tVariableN: + return getPluralOperand(PLURAL_OPERAND_N); + case tVariableI: + return getPluralOperand(PLURAL_OPERAND_I); + case tVariableF: + return getPluralOperand(PLURAL_OPERAND_F); + case tVariableV: + return getPluralOperand(PLURAL_OPERAND_V); + case tVariableT: + return getPluralOperand(PLURAL_OPERAND_T); + default: + U_ASSERT(FALSE); // unexpected. + return 0.0; + } + } + + virtual bool isNaN() const = 0; + + virtual bool isInfinite() const = 0; +}; + /** * class FixedDecimal serves to communicate the properties * of a formatted number from a decimal formatter to PluralRules::select() @@ -184,7 +266,7 @@ private: * see DecimalFormat::getFixedDecimal() * @internal */ -class U_I18N_API FixedDecimal: public UMemory { +class U_I18N_API FixedDecimal: public IFixedDecimal, public UObject { public: /** * @param n the number, e.g. 12.345 @@ -196,10 +278,16 @@ class U_I18N_API FixedDecimal: public UMemory { explicit FixedDecimal(double n); explicit FixedDecimal(const VisibleDigits &n); FixedDecimal(); + ~FixedDecimal() override = default; FixedDecimal(const UnicodeString &s, UErrorCode &ec); FixedDecimal(const FixedDecimal &other); - double get(tokenType operand) const; + double getPluralOperand(PluralOperand operand) const override; + bool isNaN() const override; + bool isInfinite() const override; + + bool isNanOrInfinity() const; // used in decimfmtimpl.cpp + int32_t getVisibleFractionDigitCount() const; void init(double n, int32_t v, int64_t f); @@ -217,7 +305,8 @@ class U_I18N_API FixedDecimal: public UMemory { int64_t intValue; UBool hasIntegerValue; UBool isNegative; - UBool isNanOrInfinity; + UBool _isNaN; + UBool _isInfinite; }; class AndConstraint : public UMemory { @@ -240,7 +329,7 @@ public: virtual ~AndConstraint(); AndConstraint* add(); // UBool isFulfilled(double number); - UBool isFulfilled(const FixedDecimal &number); + UBool isFulfilled(const IFixedDecimal &number); }; class OrConstraint : public UMemory { @@ -253,7 +342,7 @@ public: virtual ~OrConstraint(); AndConstraint* add(); // UBool isFulfilled(double number); - UBool isFulfilled(const FixedDecimal &number); + UBool isFulfilled(const IFixedDecimal &number); }; class RuleChain : public UMemory { @@ -271,7 +360,7 @@ public: RuleChain(const RuleChain& other); virtual ~RuleChain(); - UnicodeString select(const FixedDecimal &number) const; + UnicodeString select(const IFixedDecimal &number) const; void dumpRules(UnicodeString& result); UErrorCode getKeywords(int32_t maxArraySize, UnicodeString *keywords, int32_t& arraySize) const; UBool isKeyword(const UnicodeString& keyword) const; diff --git a/icu4c/source/i18n/unicode/plurrule.h b/icu4c/source/i18n/unicode/plurrule.h index a14f392b7a2..16e1a8b3567 100644 --- a/icu4c/source/i18n/unicode/plurrule.h +++ b/icu4c/source/i18n/unicode/plurrule.h @@ -43,7 +43,7 @@ U_NAMESPACE_BEGIN class Hashtable; -class FixedDecimal; +class IFixedDecimal; class VisibleDigitsWithExponent; class RuleChain; class PluralRuleParser; @@ -367,7 +367,7 @@ public: /** * @internal */ - UnicodeString select(const FixedDecimal &number) const; + UnicodeString select(const IFixedDecimal &number) const; /** * @internal */ diff --git a/icu4c/source/test/intltest/dcfmapts.cpp b/icu4c/source/test/intltest/dcfmapts.cpp index 03c1ca89d4f..b4639f73a45 100644 --- a/icu4c/source/test/intltest/dcfmapts.cpp +++ b/icu4c/source/test/intltest/dcfmapts.cpp @@ -773,11 +773,11 @@ void IntlTestDecimalFormatAPI::TestFixedDecimal() { fd = df->getFixedDecimal(uprv_getInfinity(), status); TEST_ASSERT_STATUS(status); - ASSERT_EQUAL(TRUE, fd.isNanOrInfinity); + ASSERT_EQUAL(TRUE, fd.isNanOrInfinity()); fd = df->getFixedDecimal(0.0, status); - ASSERT_EQUAL(FALSE, fd.isNanOrInfinity); + ASSERT_EQUAL(FALSE, fd.isNanOrInfinity()); fd = df->getFixedDecimal(uprv_getNaN(), status); - ASSERT_EQUAL(TRUE, fd.isNanOrInfinity); + ASSERT_EQUAL(TRUE, fd.isNanOrInfinity()); TEST_ASSERT_STATUS(status); // Test Big Decimal input. -- 2.40.0