Skip to content

Commit

Permalink
Update CharString to use int64_t for appendNumber and add getConstant…
Browse files Browse the repository at this point in the history
…sString function
  • Loading branch information
younies committed Feb 3, 2025
1 parent bf675e3 commit 106fc02
Show file tree
Hide file tree
Showing 4 changed files with 88 additions and 6 deletions.
2 changes: 1 addition & 1 deletion icu4c/source/common/charstr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ CharString &CharString::append(const char *s, int32_t sLength, UErrorCode &error
return *this;
}

CharString &CharString::appendNumber(int32_t number, UErrorCode &status) {
CharString &CharString::appendNumber(int64_t number, UErrorCode &status) {
if (number < 0) {
this->append('-', status);
if (U_FAILURE(status)) {
Expand Down
2 changes: 1 addition & 1 deletion icu4c/source/common/charstr.h
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ class U_COMMON_API CharString : public UMemory {
}
CharString &append(const char *s, int32_t sLength, UErrorCode &status);

CharString &appendNumber(int32_t number, UErrorCode &status);
CharString &appendNumber(int64_t number, UErrorCode &status);

/**
* Returns a writable buffer for appending and writes the buffer's capacity to
Expand Down
53 changes: 49 additions & 4 deletions icu4c/source/i18n/measunit_extra.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1269,6 +1269,51 @@ MeasureUnitImpl::extractIndividualUnitsWithIndices(UErrorCode &status) const {
return result;
}

int32_t countCharacter(const CharString &str, char c) {
int32_t count = 0;
for (int32_t i = 0, n = str.length(); i < n; i++) {
if (str[i] == c) {
count++;
}
}
return count;
}

/**
* Internal function that returns a string of the constants in the correct
* format.
*
* Example:
* 1000 --> "-per-1000"
* 1000000 --> "-per-1e6"
*
* NOTE: this function is only used when the constant denominator is greater
* than 0.
*/
CharString getConstantsString(uint64_t constantDenominator, UErrorCode &status) {
U_ASSERT(constantDenominator > 0 && constantDenominator <= LONG_MAX);

CharString result;
result.appendNumber(constantDenominator, status);
if (U_FAILURE(status)) {
return result;
}

if (constantDenominator <= 1000) {
return result;
}

// Check if the constant is a power of 10.
int32_t zeros = countCharacter(result, '0');
if (zeros == result.length() - 1 && result[0] == '1') {
result.clear();
result.append(StringPiece("1e"), status);
result.appendNumber(zeros, status);
}

return result;
}

/**
* Normalize a MeasureUnitImpl and generate the identifier string in place.
*/
Expand Down Expand Up @@ -1319,8 +1364,8 @@ void MeasureUnitImpl::serialize(UErrorCode &status) {
result.append(StringPiece("-per-"), status);
}

if (this->constantDenominator != 0) {
result.appendNumber(this->constantDenominator, status);
if (this->constantDenominator > 0) {
result.append(getConstantsString(this->constantDenominator, status), status);
result.append(StringPiece("-"), status);
constantDenominatorAppended = true;
}
Expand All @@ -1333,9 +1378,9 @@ void MeasureUnitImpl::serialize(UErrorCode &status) {
this->singleUnits[i]->appendNeutralIdentifier(result, status);
}

if (!constantDenominatorAppended && this->constantDenominator != 0) {
if (!constantDenominatorAppended && this->constantDenominator > 0) {
result.append(StringPiece("-per-"), status);
result.appendNumber(this->constantDenominator, status);
result.append(getConstantsString(this->constantDenominator, status), status);
}

if (U_FAILURE(status)) {
Expand Down
37 changes: 37 additions & 0 deletions icu4c/source/test/intltest/units_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ class UnitsTest : public IntlTest {
void testUnitPreferencesWithCLDRTests();
void testUnitsConstantsDenomenator();
void testMeasureUnit_withConstantDenominator();
void testUnitsConstantsDenomenator_getIdentifier();
void testConverter();
};

Expand All @@ -72,6 +73,7 @@ void UnitsTest::runIndexedTest(int32_t index, UBool exec, const char *&name, cha
TESTCASE_AUTO(testUnitPreferencesWithCLDRTests);
TESTCASE_AUTO(testUnitsConstantsDenomenator);
TESTCASE_AUTO(testMeasureUnit_withConstantDenominator);
TESTCASE_AUTO(testUnitsConstantsDenomenator_getIdentifier);
TESTCASE_AUTO(testConverter);
TESTCASE_AUTO_END;
}
Expand Down Expand Up @@ -1342,4 +1344,39 @@ void UnitsTest::testMeasureUnit_withConstantDenominator() {
status.reset();
}

void UnitsTest::testUnitsConstantsDenomenator_getIdentifier() {
IcuTestErrorCode status(*this, "UnitTests::testUnitsConstantsDenomenator_getIdentifier");

// Test Cases
struct TestCase {
const char *source;
const char *expectedIdentifier;
} testCases[]{
{"meter-per-1000", "meter-per-1000"},
{"meter-per-1000-kilometer", "meter-per-1000-kilometer"},
{"meter-per-1000000", "meter-per-1e6"},
{"meter-per-1000000-kilometer", "meter-per-1e6-kilometer"},
{"meter-per-1000000000", "meter-per-1e9"},
{"meter-per-1000000000-kilometer", "meter-per-1e9-kilometer"},
{"meter-per-1000000000000", "meter-per-1e12"},
{"meter-per-1000000000000-kilometer", "meter-per-1e12-kilometer"},
{"meter-per-1000000000000000", "meter-per-1e15"},
{"meter-per-1e15-kilometer", "meter-per-1e15-kilometer"},
{"meter-per-1000000000000000000", "meter-per-1e18"},
{"meter-per-1e18-kilometer", "meter-per-1e18-kilometer"},
{"meter-per-1000000000000001", "meter-per-1000000000000001"},
{"meter-per-1000000000000001-kilometer", "meter-per-1000000000000001-kilometer"},
};

for (const auto &testCase : testCases) {
MeasureUnit unit = MeasureUnit::forIdentifier(testCase.source, status);
if (status.errIfFailureAndReset("forIdentifier(\"%s\")", testCase.source)) {
continue;
}

auto actualIdentifier = unit.getIdentifier();
assertEquals(" getIdentifier(\"%s\")", testCase.expectedIdentifier, actualIdentifier);
}
}

#endif /* #if !UCONFIG_NO_FORMATTING */

0 comments on commit 106fc02

Please sign in to comment.