Skip to content

Commit

Permalink
ICU-21519 Add PluralOperand 'c' as alias to 'e', parse FixedDecimal s…
Browse files Browse the repository at this point in the history
…trings
  • Loading branch information
echeran committed Mar 8, 2021
1 parent ce640dc commit e2f21c7
Show file tree
Hide file tree
Showing 11 changed files with 482 additions and 161 deletions.
3 changes: 3 additions & 0 deletions icu4c/source/i18n/number_decimalquantity.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,9 @@ double DecimalQuantity::getPluralOperand(PluralOperand operand) const {
return fractionCountWithoutTrailingZeros();
case PLURAL_OPERAND_E:
return static_cast<double>(getExponent());
case PLURAL_OPERAND_C:
// Plural operand `c` is currently an alias for `e`.
return static_cast<double>(getExponent());
default:
return std::abs(toDouble());
}
Expand Down
49 changes: 43 additions & 6 deletions icu4c/source/i18n/plurrule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ static const UChar PK_VAR_I[]={LOW_I,0};
static const UChar PK_VAR_F[]={LOW_F,0};
static const UChar PK_VAR_T[]={LOW_T,0};
static const UChar PK_VAR_E[]={LOW_E,0};
static const UChar PK_VAR_C[]={LOW_C,0};
static const UChar PK_VAR_V[]={LOW_V,0};
static const UChar PK_WITHIN[]={LOW_W,LOW_I,LOW_T,LOW_H,LOW_I,LOW_N,0};
static const UChar PK_DECIMAL[]={LOW_D,LOW_E,LOW_C,LOW_I,LOW_M,LOW_A,LOW_L,0};
Expand Down Expand Up @@ -421,7 +422,6 @@ getSamplesFromString(const UnicodeString &samples, double *destDbl,
destFd[sampleCount++] = fixed;
}
} else {

FixedDecimal fixedLo(sampleRange.tempSubStringBetween(0, tildeIndex), status);
FixedDecimal fixedHi(sampleRange.tempSubStringBetween(tildeIndex+1), status);
double rangeLo = fixedLo.source;
Expand Down Expand Up @@ -514,6 +514,7 @@ PluralRules::getSamples(const UnicodeString &keyword, FixedDecimal *dest,
if (rc == nullptr) {
return 0;
}

int32_t numSamples = getSamplesFromString(rc->fIntegerSamples, nullptr, dest, destCapacity, status);
if (numSamples == 0) {
numSamples = getSamplesFromString(rc->fDecimalSamples, nullptr, dest, destCapacity, status);
Expand Down Expand Up @@ -706,6 +707,7 @@ PluralRuleParser::parse(const UnicodeString& ruleData, PluralRules *prules, UErr
case tVariableF:
case tVariableT:
case tVariableE:
case tVariableC:
case tVariableV:
U_ASSERT(curAndConstraint != nullptr);
curAndConstraint->digitsType = type;
Expand Down Expand Up @@ -1092,6 +1094,8 @@ static UnicodeString tokenString(tokenType tok) {
s.append(LOW_T); break;
case tVariableE:
s.append(LOW_E); break;
case tVariableC:
s.append(LOW_C); break;
default:
s.append(TILDE);
}
Expand Down Expand Up @@ -1269,6 +1273,7 @@ PluralRuleParser::checkSyntax(UErrorCode &status)
case tVariableF:
case tVariableT:
case tVariableE:
case tVariableC:
case tVariableV:
if (type != tIs && type != tMod && type != tIn &&
type != tNot && type != tWithin && type != tEqual && type != tNotEqual) {
Expand All @@ -1286,6 +1291,7 @@ PluralRuleParser::checkSyntax(UErrorCode &status)
type == tVariableF ||
type == tVariableT ||
type == tVariableE ||
type == tVariableC ||
type == tVariableV ||
type == tAt)) {
status = U_UNEXPECTED_TOKEN;
Expand Down Expand Up @@ -1318,6 +1324,7 @@ PluralRuleParser::checkSyntax(UErrorCode &status)
type != tVariableF &&
type != tVariableT &&
type != tVariableE &&
type != tVariableC &&
type != tVariableV) {
status = U_UNEXPECTED_TOKEN;
}
Expand Down Expand Up @@ -1497,6 +1504,8 @@ PluralRuleParser::getKeyType(const UnicodeString &token, tokenType keyType)
keyType = tVariableT;
} else if (0 == token.compare(PK_VAR_E, 1)) {
keyType = tVariableE;
} else if (0 == token.compare(PK_VAR_C, 1)) {
keyType = tVariableC;
} else if (0 == token.compare(PK_VAR_V, 1)) {
keyType = tVariableV;
} else if (0 == token.compare(PK_IS, 2)) {
Expand Down Expand Up @@ -1596,11 +1605,17 @@ PluralOperand tokenTypeToPluralOperand(tokenType tt) {
return PLURAL_OPERAND_T;
case tVariableE:
return PLURAL_OPERAND_E;
case tVariableC:
return PLURAL_OPERAND_E;
default:
UPRV_UNREACHABLE; // unexpected.
}
}

FixedDecimal::FixedDecimal(double n, int32_t v, int64_t f, int32_t e, int32_t c) {
init(n, v, f, e, c);
}

FixedDecimal::FixedDecimal(double n, int32_t v, int64_t f, int32_t e) {
init(n, v, f, e);
// check values. TODO make into unit test.
Expand Down Expand Up @@ -1642,16 +1657,30 @@ FixedDecimal::FixedDecimal() {
FixedDecimal::FixedDecimal(const UnicodeString &num, UErrorCode &status) {
CharString cs;
int32_t parsedExponent = 0;
int32_t parsedCompactExponent = 0;

int32_t exponentIdx = num.indexOf(u'e');
if (exponentIdx < 0) {
exponentIdx = num.indexOf(u'E');
}
int32_t compactExponentIdx = num.indexOf(u'c');
if (compactExponentIdx < 0) {
compactExponentIdx = num.indexOf(u'C');
}

if (exponentIdx >= 0) {
cs.appendInvariantChars(num.tempSubString(0, exponentIdx), status);
int32_t expSubstrStart = exponentIdx + 1;
parsedExponent = ICU_Utility::parseAsciiInteger(num, expSubstrStart);
}
else if (compactExponentIdx >= 0) {
cs.appendInvariantChars(num.tempSubString(0, compactExponentIdx), status);
int32_t expSubstrStart = compactExponentIdx + 1;
parsedCompactExponent = ICU_Utility::parseAsciiInteger(num, expSubstrStart);

parsedExponent = parsedCompactExponent;
exponentIdx = compactExponentIdx;
}
else {
cs.appendInvariantChars(num, status);
}
Expand Down Expand Up @@ -1706,13 +1735,20 @@ void FixedDecimal::init(double n, int32_t v, int64_t f) {
init(n, v, f, exponent);
}


void FixedDecimal::init(double n, int32_t v, int64_t f, int32_t e) {
// Currently, `c` is an alias for `e`
init(n, v, f, e, e);
}

void FixedDecimal::init(double n, int32_t v, int64_t f, int32_t e, int32_t c) {
isNegative = n < 0.0;
source = fabs(n);
_isNaN = uprv_isNaN(source);
_isInfinite = uprv_isInfinite(source);
exponent = e;
if (exponent == 0) {
exponent = c;
}
if (_isNaN || _isInfinite) {
v = 0;
f = 0;
Expand Down Expand Up @@ -1843,6 +1879,7 @@ double FixedDecimal::getPluralOperand(PluralOperand operand) const {
case PLURAL_OPERAND_T: return static_cast<double>(decimalDigitsWithoutTrailingZeros);
case PLURAL_OPERAND_V: return visibleDecimalDigitCount;
case PLURAL_OPERAND_E: return exponent;
case PLURAL_OPERAND_C: return exponent;
default:
UPRV_UNREACHABLE; // unexpected.
}
Expand Down Expand Up @@ -1876,12 +1913,12 @@ bool FixedDecimal::operator==(const FixedDecimal &other) const {
UnicodeString FixedDecimal::toString() const {
char pattern[15];
char buffer[20];
if (exponent == 0) {
snprintf(pattern, sizeof(pattern), "%%.%df", visibleDecimalDigitCount);
snprintf(buffer, sizeof(buffer), pattern, source);
} else {
if (exponent != 0) {
snprintf(pattern, sizeof(pattern), "%%.%dfe%%d", visibleDecimalDigitCount);
snprintf(buffer, sizeof(buffer), pattern, source, exponent);
} else {
snprintf(pattern, sizeof(pattern), "%%.%df", visibleDecimalDigitCount);
snprintf(buffer, sizeof(buffer), pattern, source);
}
return UnicodeString(buffer, -1, US_INV);
}
Expand Down
19 changes: 16 additions & 3 deletions icu4c/source/i18n/plurrule_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ enum tokenType {
tVariableV,
tVariableT,
tVariableE,
tVariableC,
tDecimal,
tInteger,
tEOF
Expand Down Expand Up @@ -222,11 +223,20 @@ enum PluralOperand {
PLURAL_OPERAND_W,

/**
* Suppressed exponent for compact notation (exponent needed in
* scientific notation with compact notation to approximate i).
* Suppressed exponent for scientific notation (exponent needed in
* scientific notation to approximate i).
*/
PLURAL_OPERAND_E,

/**
* This operand is currently treated as an alias for `PLURAL_OPERAND_E`.
* In the future, it will represent:
*
* Suppressed exponent for compact notation (exponent needed in
* compact notation to approximate i).
*/
PLURAL_OPERAND_C,

/**
* THIS OPERAND IS DEPRECATED AND HAS BEEN REMOVED FROM THE SPEC.
*
Expand Down Expand Up @@ -280,8 +290,10 @@ class U_I18N_API FixedDecimal: public IFixedDecimal, public UObject {
* @param n the number, e.g. 12.345
* @param v The number of visible fraction digits, e.g. 3
* @param f The fraction digits, e.g. 345
* @param e The exponent, e.g. 7 in 1.2e7 (for compact/scientific)
* @param e The exponent, e.g. 7 in 1.2e7, for scientific notation
* @param c Currently: an alias for param `e`.
*/
FixedDecimal(double n, int32_t v, int64_t f, int32_t e, int32_t c);
FixedDecimal(double n, int32_t v, int64_t f, int32_t e);
FixedDecimal(double n, int32_t v, int64_t f);
FixedDecimal(double n, int32_t);
Expand All @@ -302,6 +314,7 @@ class U_I18N_API FixedDecimal: public IFixedDecimal, public UObject {

int32_t getVisibleFractionDigitCount() const;

void init(double n, int32_t v, int64_t f, int32_t e, int32_t c);
void init(double n, int32_t v, int64_t f, int32_t e);
void init(double n, int32_t v, int64_t f);
void init(double n);
Expand Down
2 changes: 1 addition & 1 deletion icu4c/source/test/intltest/numbertest.h
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ class DecimalQuantityTest : public IntlTest {
void testToDouble();
void testMaxDigits();
void testNickelRounding();
void testCompactDecimalSuppressedExponent();
void testScientificAndCompactSuppressedExponent();
void testSuppressedExponentUnchangedByInitialScaling();

void runIndexedTest(int32_t index, UBool exec, const char *&name, char *par = 0);
Expand Down
Loading

0 comments on commit e2f21c7

Please sign in to comment.