ICU-13177 Adding IFixedDecimal interface to C++.

X-SVN-Rev: 40391
This commit is contained in:
Shane Carr 2017-09-13 07:49:26 +00:00
parent 082cbac7fc
commit 1f1a485c3c
5 changed files with 135 additions and 30 deletions

View file

@ -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,

View file

@ -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;
}

View file

@ -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.
*
* <p>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".
*
* <p>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;

View file

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

View file

@ -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.