Skip to content

Commit

Permalink
ICU-22692 Change SimpleNumber truncateAt to setMaximumIntegerDigits
Browse files Browse the repository at this point in the history
Also promotes the remaining draft SimpleNumber functions to stable.

See #2892
  • Loading branch information
sffc committed Mar 26, 2024
1 parent 57fc309 commit 8a1df5a
Show file tree
Hide file tree
Showing 14 changed files with 234 additions and 49 deletions.
9 changes: 7 additions & 2 deletions icu4c/source/i18n/number_capi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -309,12 +309,17 @@ usnum_setMinimumFractionDigits(USimpleNumber* unumber, int32_t minimumFractionDi
}

U_CAPI void U_EXPORT2
usnum_truncateStart(USimpleNumber* unumber, int32_t maximumIntegerDigits, UErrorCode* ec) {
usnum_setMaximumIntegerDigits(USimpleNumber* unumber, int32_t maximumIntegerDigits, UErrorCode* ec) {
auto* number = USimpleNumberData::validate(unumber, *ec);
if (U_FAILURE(*ec)) {
return;
}
number->fNumber.truncateStart(maximumIntegerDigits, *ec);
number->fNumber.setMaximumIntegerDigits(maximumIntegerDigits, *ec);
}

U_CAPI void U_EXPORT2
usnum_truncateStart(USimpleNumber* unumber, int32_t maximumIntegerDigits, UErrorCode* ec) {
usnum_setMaximumIntegerDigits(unumber, maximumIntegerDigits, ec);
}

U_CAPI void U_EXPORT2
Expand Down
18 changes: 12 additions & 6 deletions icu4c/source/i18n/number_decimalquantity.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -131,18 +131,24 @@ void DecimalQuantity::clear() {
setBcdToZero(); // sets scale, precision, hasDouble, origDouble, origDelta, and BCD data
}

void DecimalQuantity::setMinInteger(int32_t minInt) {
void DecimalQuantity::decreaseMinIntegerTo(int32_t minInt) {
// Validation should happen outside of DecimalQuantity, e.g., in the Precision class.
U_ASSERT(minInt >= 0);

if (lReqPos > minInt) {
lReqPos = minInt;
}
}

void DecimalQuantity::increaseMinIntegerTo(int32_t minInt) {
// Validation should happen outside of DecimalQuantity, e.g., in the Precision class.
U_ASSERT(minInt >= 0);

// Special behavior: do not set minInt to be less than what is already set.
// This is so significant digits rounding can set the integer length.
if (minInt < lReqPos) {
minInt = lReqPos;
if (lReqPos < minInt) {
lReqPos = minInt;
}

// Save values into internal state
lReqPos = minInt;
}

void DecimalQuantity::setMinFraction(int32_t minFrac) {
Expand Down
10 changes: 9 additions & 1 deletion icu4c/source/i18n/number_decimalquantity.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,13 +52,21 @@ class U_I18N_API DecimalQuantity : public IFixedDecimal, public UMemory {
/** Move assignment */
DecimalQuantity &operator=(DecimalQuantity&& src) noexcept;

/**
* If the minimum integer digits are greater than `minInt`,
* sets it to `minInt`.
*
* @param minInt The minimum number of integer digits.
*/
void decreaseMinIntegerTo(int32_t minInt);

/**
* Sets the minimum integer digits that this {@link DecimalQuantity} should generate.
* This method does not perform rounding.
*
* @param minInt The minimum number of integer digits.
*/
void setMinInteger(int32_t minInt);
void increaseMinIntegerTo(int32_t minInt);

/**
* Sets the minimum fraction digits that this {@link DecimalQuantity} should generate.
Expand Down
4 changes: 2 additions & 2 deletions icu4c/source/i18n/number_integerwidth.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,14 +46,14 @@ void IntegerWidth::apply(impl::DecimalQuantity& quantity, UErrorCode& status) co
if (fHasError) {
status = U_ILLEGAL_ARGUMENT_ERROR;
} else if (fUnion.minMaxInt.fMaxInt == -1) {
quantity.setMinInteger(fUnion.minMaxInt.fMinInt);
quantity.increaseMinIntegerTo(fUnion.minMaxInt.fMinInt);
} else {
// Enforce the backwards-compatibility feature "FormatFailIfMoreThanMaxDigits"
if (fUnion.minMaxInt.fFormatFailIfMoreThanMaxDigits &&
fUnion.minMaxInt.fMaxInt < quantity.getMagnitude()) {
status = U_ILLEGAL_ARGUMENT_ERROR;
}
quantity.setMinInteger(fUnion.minMaxInt.fMinInt);
quantity.increaseMinIntegerTo(fUnion.minMaxInt.fMinInt);
quantity.applyMaxInteger(fUnion.minMaxInt.fMaxInt);
}
}
Expand Down
2 changes: 1 addition & 1 deletion icu4c/source/i18n/number_patternstring.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -768,7 +768,7 @@ UnicodeString PatternStringUtils::propertiesToPatternString(const DecimalFormatP
incrementQuantity.roundToInfinity();
digitsStringScale = incrementQuantity.getLowerDisplayMagnitude();
incrementQuantity.adjustMagnitude(-digitsStringScale);
incrementQuantity.setMinInteger(minInt - digitsStringScale);
incrementQuantity.increaseMinIntegerTo(minInt - digitsStringScale);
UnicodeString str = incrementQuantity.toPlainString();
if (str.charAt(0) == u'-') {
// TODO: Unsupported operation exception or fail silently?
Expand Down
2 changes: 1 addition & 1 deletion icu4c/source/i18n/number_rounding.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -437,7 +437,7 @@ void RoundingImpl::apply(impl::DecimalQuantity &value, UErrorCode& status) const
uprv_max(0, -getDisplayMagnitudeSignificant(value, fPrecision.fUnion.fracSig.fMinSig));
// Make sure that digits are displayed on zero.
if (value.isZeroish() && fPrecision.fUnion.fracSig.fMinSig > 0) {
value.setMinInteger(1);
value.increaseMinIntegerTo(1);
}
break;

Expand Down
10 changes: 8 additions & 2 deletions icu4c/source/i18n/number_simple.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,8 @@ void SimpleNumber::setMinimumIntegerDigits(uint32_t position, UErrorCode& status
status = U_INVALID_STATE_ERROR;
return;
}
fData->quantity.setMinInteger(position);
fData->quantity.decreaseMinIntegerTo(position);
fData->quantity.increaseMinIntegerTo(position);
}

void SimpleNumber::setMinimumFractionDigits(uint32_t position, UErrorCode& status) {
Expand All @@ -95,17 +96,22 @@ void SimpleNumber::setMinimumFractionDigits(uint32_t position, UErrorCode& statu
fData->quantity.setMinFraction(position);
}

void SimpleNumber::truncateStart(uint32_t position, UErrorCode& status) {
void SimpleNumber::setMaximumIntegerDigits(uint32_t position, UErrorCode& status) {
if (U_FAILURE(status)) {
return;
}
if (fData == nullptr) {
status = U_INVALID_STATE_ERROR;
return;
}
fData->quantity.decreaseMinIntegerTo(position);
fData->quantity.applyMaxInteger(position);
}

void SimpleNumber::truncateStart(uint32_t position, UErrorCode& status) {
setMaximumIntegerDigits(position, status);
}

void SimpleNumber::setSign(USimpleNumberSign sign, UErrorCode& status) {
if (U_FAILURE(status)) {
return;
Expand Down
2 changes: 1 addition & 1 deletion icu4c/source/i18n/smpdtfmt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2164,7 +2164,7 @@ SimpleDateFormat::zeroPaddingNumber(
data.quantity.setToLong(value);
number::SimpleNumber number(&data, localStatus);
number.setMinimumIntegerDigits(minDigits, localStatus);
number.truncateStart(maxDigits, localStatus);
number.setMaximumIntegerDigits(maxDigits, localStatus);

number::FormattedNumber result = fSimpleNumberFormatter->format(std::move(number), localStatus);
if (U_FAILURE(localStatus)) {
Expand Down
33 changes: 19 additions & 14 deletions icu4c/source/i18n/unicode/simplenumberformatter.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,44 +68,49 @@ class U_I18N_API SimpleNumber : public UMemory {
*/
void multiplyByPowerOfTen(int32_t power, UErrorCode& status);

#ifndef U_HIDE_DRAFT_API
/**
* Rounds the value currently stored in the SimpleNumber to the given power of 10.
* Rounds the value currently stored in the SimpleNumber to the given power of 10,
* which can be before or after the decimal separator.
*
* This function immediately mutates the inner value.
* This function does not change minimum integer digits.
*
* @draft ICU 73
* @stable ICU 73
*/
void roundTo(int32_t power, UNumberFormatRoundingMode roundingMode, UErrorCode& status);

#ifndef U_HIDE_DRAFT_API
/**
* Truncates the most significant digits to the given maximum number of integer digits.
* Sets the number of integer digits to the given amount, truncating if necessary.
*
* This function immediately mutates the inner value.
* @draft ICU 75
*/
void setMaximumIntegerDigits(uint32_t maximumIntegerDigits, UErrorCode& status);
#endif // U_HIDE_DRAFT_API

#ifndef U_HIDE_DEPRECATED_API
/**
* Alias for setMaximumIntegerDigits.
* Will be removed after ICU 75.
*
* @draft ICU 73
* @deprecated ICU 75
*/
void truncateStart(uint32_t maximumIntegerDigits, UErrorCode& status);
#endif // U_HIDE_DEPRECATED_API

/**
* Pads the beginning of the number with zeros up to the given minimum number of integer digits.
*
* This setting is applied upon formatting the number.
*
* @draft ICU 73
* @stable ICU 73
*/
void setMinimumIntegerDigits(uint32_t minimumIntegerDigits, UErrorCode& status);

/**
* Pads the end of the number with zeros up to the given minimum number of fraction digits.
*
* This setting is applied upon formatting the number.
*
* @draft ICU 73
* @stable ICU 73
*/
void setMinimumFractionDigits(uint32_t minimumFractionDigits, UErrorCode& status);

#endif // U_HIDE_DRAFT_API
/**
* Sets the sign of the number: an explicit plus sign, explicit minus sign, or no sign.
*
Expand Down
35 changes: 21 additions & 14 deletions icu4c/source/i18n/unicode/usimplenumberformatter.h
Original file line number Diff line number Diff line change
Expand Up @@ -126,13 +126,13 @@ U_CAPI void U_EXPORT2
usnum_multiplyByPowerOfTen(USimpleNumber* unumber, int32_t power, UErrorCode* ec);


#ifndef U_HIDE_DRAFT_API
/**
* Rounds the value currently stored in the USimpleNumber to the given power of 10.
* Rounds the value currently stored in the USimpleNumber to the given power of 10,
* which can be before or after the decimal separator.
*
* This function immediately mutates the inner value.
* This function does not change minimum integer digits.
*
* @draft ICU 73
* @stable ICU 73
*/
U_CAPI void U_EXPORT2
usnum_roundTo(USimpleNumber* unumber, int32_t power, UNumberFormatRoundingMode roundingMode, UErrorCode* ec);
Expand All @@ -141,9 +141,7 @@ usnum_roundTo(USimpleNumber* unumber, int32_t power, UNumberFormatRoundingMode r
/**
* Pads the beginning of the number with zeros up to the given minimum number of integer digits.
*
* This setting is applied upon formatting the number.
*
* @draft ICU 73
* @stable ICU 73
*/
U_CAPI void U_EXPORT2
usnum_setMinimumIntegerDigits(USimpleNumber* unumber, int32_t minimumIntegerDigits, UErrorCode* ec);
Expand All @@ -152,25 +150,34 @@ usnum_setMinimumIntegerDigits(USimpleNumber* unumber, int32_t minimumIntegerDigi
/**
* Pads the end of the number with zeros up to the given minimum number of fraction digits.
*
* This setting is applied upon formatting the number.
*
* @draft ICU 73
* @stable ICU 73
*/
U_CAPI void U_EXPORT2
usnum_setMinimumFractionDigits(USimpleNumber* unumber, int32_t minimumFractionDigits, UErrorCode* ec);


#ifndef U_HIDE_DRAFT_API
/**
* Truncates digits from the beginning of the number to the given maximum number of integer digits.
* Sets the number of integer digits to the given amount, truncating if necessary.
*
* This function immediately mutates the inner value.
* @draft ICU 75
*/
U_CAPI void U_EXPORT2
usnum_setMaximumIntegerDigits(USimpleNumber* unumber, int32_t maximumIntegerDigits, UErrorCode* ec);
#endif // U_HIDE_DRAFT_API


#ifndef U_HIDE_DEPRECATED_API
/**
* Alias for setMaximumIntegerDigits.
* Will be removed after ICU 75.
*
* @draft ICU 73
* @deprecated ICU 75
*/
U_CAPI void U_EXPORT2
usnum_truncateStart(USimpleNumber* unumber, int32_t maximumIntegerDigits, UErrorCode* ec);
#endif // U_HIDE_DEPRECATED_API

#endif // U_HIDE_DRAFT_API

/**
* Sets the sign of the number: an explicit plus sign, explicit minus sign, or no sign.
Expand Down
2 changes: 1 addition & 1 deletion icu4c/source/test/cintltst/unumberformattertst.c
Original file line number Diff line number Diff line change
Expand Up @@ -255,9 +255,9 @@ static void TestSimpleNumberFormatterFull(void) {
usnum_setToInt64(unumber, 98765, &ec);
usnum_multiplyByPowerOfTen(unumber, -2, &ec);
usnum_roundTo(unumber, -1, UNUM_ROUND_HALFDOWN, &ec);
usnum_setMaximumIntegerDigits(unumber, 1, &ec);
usnum_setMinimumIntegerDigits(unumber, 4, &ec);
usnum_setMinimumFractionDigits(unumber, 3, &ec);
usnum_truncateStart(unumber, 1, &ec);
usnum_setSign(unumber, UNUM_SIMPLE_NUMBER_PLUS_SIGN, &ec);

usnumf_format(uformatter, unumber, uresult, &ec);
Expand Down
1 change: 1 addition & 0 deletions icu4c/source/test/intltest/numbertest.h
Original file line number Diff line number Diff line change
Expand Up @@ -373,6 +373,7 @@ class SimpleNumberFormatterTest : public IntlTestWithFieldPosition {
public:
void testBasic();
void testWithOptions();
void testDigits();
void testSymbols();
void testSign();
void testCopyMove();
Expand Down
4 changes: 2 additions & 2 deletions icu4c/source/test/intltest/numbertest_decimalquantity.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@ void DecimalQuantityTest::testDecimalQuantityBehaviorStandalone() {

fq.setToLong(90909090909000L);
assertToStringAndHealth(fq, u"<DecimalQuantity 0:0 long 90909090909E3>");
fq.setMinInteger(2);
fq.increaseMinIntegerTo(2);
fq.applyMaxInteger(5);
assertToStringAndHealth(fq, u"<DecimalQuantity 2:0 long 9E3>");
fq.setMinFraction(3);
Expand Down Expand Up @@ -424,7 +424,7 @@ void DecimalQuantityTest::testMaxDigits() {
DecimalQuantity dq;
dq.setToDouble(876.543);
dq.roundToInfinity();
dq.setMinInteger(0);
dq.increaseMinIntegerTo(0);
dq.applyMaxInteger(2);
dq.setMinFraction(0);
dq.roundToMagnitude(-2, UNUM_ROUND_FLOOR, status);
Expand Down

0 comments on commit 8a1df5a

Please sign in to comment.