mirror of
https://github.com/unicode-org/icu.git
synced 2025-04-08 06:53:45 +00:00
Implementing sequence units and fixing bugs
This commit is contained in:
parent
05ec2aea59
commit
6369aba35a
3 changed files with 272 additions and 92 deletions
|
@ -378,9 +378,9 @@ public:
|
|||
* @param p simple pointer to an array of T objects that is adopted
|
||||
* @stable ICU 4.4
|
||||
*/
|
||||
explicit LocalArray(T *p=NULL) : LocalPointerBase<T>(p) {}
|
||||
explicit LocalArray(T *p=nullptr) : LocalPointerBase<T>(p), fLength(p==nullptr?0:-1) {}
|
||||
/**
|
||||
* Constructor takes ownership and reports an error if NULL.
|
||||
* Constructor takes ownership and reports an error if nullptr.
|
||||
*
|
||||
* This constructor is intended to be used with other-class constructors
|
||||
* that may report a failure UErrorCode,
|
||||
|
@ -389,11 +389,11 @@ public:
|
|||
*
|
||||
* @param p simple pointer to an array of T objects that is adopted
|
||||
* @param errorCode in/out UErrorCode, set to U_MEMORY_ALLOCATION_ERROR
|
||||
* if p==NULL and no other failure code had been set
|
||||
* if p==nullptr and no other failure code had been set
|
||||
* @stable ICU 56
|
||||
*/
|
||||
LocalArray(T *p, UErrorCode &errorCode) : LocalPointerBase<T>(p) {
|
||||
if(p==NULL && U_SUCCESS(errorCode)) {
|
||||
LocalArray(T *p, UErrorCode &errorCode) : LocalArray<T>(p) {
|
||||
if(p==nullptr && U_SUCCESS(errorCode)) {
|
||||
errorCode=U_MEMORY_ALLOCATION_ERROR;
|
||||
}
|
||||
}
|
||||
|
@ -402,8 +402,8 @@ public:
|
|||
* @param src source smart pointer
|
||||
* @stable ICU 56
|
||||
*/
|
||||
LocalArray(LocalArray<T> &&src) U_NOEXCEPT : LocalPointerBase<T>(src.ptr) {
|
||||
src.ptr=NULL;
|
||||
LocalArray(LocalArray<T> &&src) U_NOEXCEPT : LocalArray<T>(src.ptr) {
|
||||
src.ptr=nullptr;
|
||||
}
|
||||
|
||||
static LocalArray<T> withLength(T *p, int32_t length) {
|
||||
|
@ -422,7 +422,7 @@ public:
|
|||
* @draft ICU 64
|
||||
*/
|
||||
explicit LocalArray(std::unique_ptr<T[]> &&p)
|
||||
: LocalPointerBase<T>(p.release()) {}
|
||||
: LocalArray<T>(p.release()) {}
|
||||
#endif /* U_HIDE_DRAFT_API */
|
||||
|
||||
/**
|
||||
|
@ -442,7 +442,8 @@ public:
|
|||
LocalArray<T> &operator=(LocalArray<T> &&src) U_NOEXCEPT {
|
||||
delete[] LocalPointerBase<T>::ptr;
|
||||
LocalPointerBase<T>::ptr=src.ptr;
|
||||
src.ptr=NULL;
|
||||
src.ptr=nullptr;
|
||||
fLength=src.fLength;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
@ -457,6 +458,7 @@ public:
|
|||
*/
|
||||
LocalArray<T> &operator=(std::unique_ptr<T[]> &&p) U_NOEXCEPT {
|
||||
adoptInstead(p.release());
|
||||
fLength=-1;
|
||||
return *this;
|
||||
}
|
||||
#endif /* U_HIDE_DRAFT_API */
|
||||
|
@ -470,6 +472,9 @@ public:
|
|||
T *temp=LocalPointerBase<T>::ptr;
|
||||
LocalPointerBase<T>::ptr=other.ptr;
|
||||
other.ptr=temp;
|
||||
int32_t tempLength=fLength;
|
||||
fLength=other.fLength;
|
||||
other.fLength=tempLength;
|
||||
}
|
||||
/**
|
||||
* Non-member LocalArray swap function.
|
||||
|
@ -489,6 +494,7 @@ public:
|
|||
void adoptInstead(T *p) {
|
||||
delete[] LocalPointerBase<T>::ptr;
|
||||
LocalPointerBase<T>::ptr=p;
|
||||
fLength=-1;
|
||||
}
|
||||
/**
|
||||
* Deletes the array it owns,
|
||||
|
@ -515,6 +521,7 @@ public:
|
|||
} else {
|
||||
delete[] p;
|
||||
}
|
||||
fLength=-1;
|
||||
}
|
||||
/**
|
||||
* Array item access (writable).
|
||||
|
|
|
@ -312,9 +312,14 @@ struct SingleUnit {
|
|||
int8_t power = 1;
|
||||
UMeasureSIPrefix siPrefix = UMEASURE_SI_PREFIX_ONE;
|
||||
int32_t simpleUnitIndex = 0;
|
||||
StringPiece id;
|
||||
StringPiece id = "one";
|
||||
|
||||
void appendTo(CharString& builder, UErrorCode& status) const {
|
||||
if (simpleUnitIndex == 0) {
|
||||
// Don't propagate SI prefixes and powers on one
|
||||
builder.append("one", status);
|
||||
return;
|
||||
}
|
||||
int8_t posPower = power < 0 ? -power : power;
|
||||
if (posPower == 0) {
|
||||
status = U_ILLEGAL_ARGUMENT_ERROR;
|
||||
|
@ -353,6 +358,18 @@ struct SingleUnit {
|
|||
|
||||
builder.append(id, status);
|
||||
}
|
||||
|
||||
char* build(UErrorCode& status) {
|
||||
if (U_FAILURE(status)) {
|
||||
return nullptr;
|
||||
}
|
||||
CharString builder;
|
||||
if (power < 0) {
|
||||
builder.append("one-per-", status);
|
||||
}
|
||||
appendTo(builder, status);
|
||||
return builder.cloneData(status);
|
||||
}
|
||||
};
|
||||
|
||||
class CompoundUnit {
|
||||
|
@ -367,7 +384,7 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
void reciprocal() {
|
||||
void takeReciprocal() {
|
||||
auto temp = std::move(numerator);
|
||||
numerator = std::move(denominator);
|
||||
denominator = std::move(temp);
|
||||
|
@ -377,14 +394,23 @@ public:
|
|||
if (numerator.length() == 0) {
|
||||
builder.append("one", status);
|
||||
} else {
|
||||
appendToImpl(numerator, numerator.length(), builder, status);
|
||||
appendToImpl(numerator, builder, status);
|
||||
}
|
||||
if (denominator.length() > 0) {
|
||||
builder.append("-per-", status);
|
||||
appendToImpl(denominator, denominator.length(), builder, status);
|
||||
appendToImpl(denominator, builder, status);
|
||||
}
|
||||
}
|
||||
|
||||
char* build(UErrorCode& status) {
|
||||
if (U_FAILURE(status)) {
|
||||
return nullptr;
|
||||
}
|
||||
CharString builder;
|
||||
appendTo(builder, status);
|
||||
return builder.cloneData(status);
|
||||
}
|
||||
|
||||
const SingleUnitList& getNumeratorUnits() const {
|
||||
return numerator;
|
||||
}
|
||||
|
@ -397,12 +423,17 @@ public:
|
|||
return numerator.length() + denominator.length() == 1;
|
||||
}
|
||||
|
||||
bool isEmpty() const {
|
||||
return numerator.length() + denominator.length() == 0;
|
||||
}
|
||||
|
||||
private:
|
||||
SingleUnitList numerator;
|
||||
SingleUnitList denominator;
|
||||
|
||||
void appendToImpl(const SingleUnitList& unitList, int32_t len, CharString& builder, UErrorCode& status) const {
|
||||
void appendToImpl(const SingleUnitList& unitList, CharString& builder, UErrorCode& status) const {
|
||||
bool first = true;
|
||||
int32_t len = unitList.length();
|
||||
for (int32_t i = 0; i < len; i++) {
|
||||
if (first) {
|
||||
first = false;
|
||||
|
@ -433,17 +464,63 @@ private:
|
|||
}
|
||||
};
|
||||
|
||||
class UnitIdentifierParser {
|
||||
class SequenceUnit {
|
||||
public:
|
||||
static UnitIdentifierParser from(StringPiece source, UErrorCode& status) {
|
||||
typedef MaybeStackVector<CompoundUnit, 3> CompoundUnitList;
|
||||
|
||||
void append(CompoundUnit&& compoundUnit, UErrorCode& status) {
|
||||
CompoundUnit* destination = units.emplaceBack();
|
||||
if (!destination) {
|
||||
status = U_MEMORY_ALLOCATION_ERROR;
|
||||
return;
|
||||
}
|
||||
*destination = std::move(compoundUnit);
|
||||
}
|
||||
|
||||
void appendTo(CharString& builder, UErrorCode& status) const {
|
||||
if (units.length() == 0) {
|
||||
builder.append("one", status);
|
||||
return;
|
||||
}
|
||||
bool isFirst = true;
|
||||
for (int32_t i = 0; i < units.length(); i++) {
|
||||
if (isFirst) {
|
||||
isFirst = false;
|
||||
} else {
|
||||
builder.append('+', status);
|
||||
}
|
||||
units[i]->appendTo(builder, status);
|
||||
}
|
||||
}
|
||||
|
||||
char* build(UErrorCode& status) {
|
||||
if (U_FAILURE(status)) {
|
||||
return UnitIdentifierParser();
|
||||
return nullptr;
|
||||
}
|
||||
CharString builder;
|
||||
appendTo(builder, status);
|
||||
return builder.cloneData(status);
|
||||
}
|
||||
|
||||
const CompoundUnitList& getUnits() const {
|
||||
return units;
|
||||
}
|
||||
|
||||
private:
|
||||
CompoundUnitList units;
|
||||
};
|
||||
|
||||
class Parser {
|
||||
public:
|
||||
static Parser from(StringPiece source, UErrorCode& status) {
|
||||
if (U_FAILURE(status)) {
|
||||
return Parser();
|
||||
}
|
||||
umtx_initOnce(gUnitExtrasInitOnce, &initUnitExtras, status);
|
||||
if (U_FAILURE(status)) {
|
||||
return UnitIdentifierParser();
|
||||
return Parser();
|
||||
}
|
||||
return UnitIdentifierParser(source);
|
||||
return Parser(source);
|
||||
}
|
||||
|
||||
bool hasNext() const {
|
||||
|
@ -474,7 +551,10 @@ public:
|
|||
int32_t previ = fIndex;
|
||||
SingleUnit singleUnit;
|
||||
nextSingleUnit(singleUnit, sawPlus, status);
|
||||
if (sawPlus) {
|
||||
if (U_FAILURE(status)) {
|
||||
return;
|
||||
}
|
||||
if (sawPlus && !result.isEmpty()) {
|
||||
fIndex = previ;
|
||||
break;
|
||||
}
|
||||
|
@ -497,6 +577,19 @@ public:
|
|||
return retval;
|
||||
}
|
||||
|
||||
SequenceUnit getOnlySequenceUnit(UErrorCode& status) {
|
||||
SequenceUnit retval;
|
||||
while (hasNext()) {
|
||||
CompoundUnit compoundUnit;
|
||||
nextCompoundUnit(compoundUnit, status);
|
||||
if (U_FAILURE(status)) {
|
||||
return retval;
|
||||
}
|
||||
retval.append(std::move(compoundUnit), status);
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
private:
|
||||
int32_t fIndex = 0;
|
||||
StringPiece fSource;
|
||||
|
@ -504,9 +597,9 @@ private:
|
|||
|
||||
bool fAfterPer = false;
|
||||
|
||||
UnitIdentifierParser() : fSource(""), fTrie(u"") {}
|
||||
Parser() : fSource(""), fTrie(u"") {}
|
||||
|
||||
UnitIdentifierParser(StringPiece source)
|
||||
Parser(StringPiece source)
|
||||
: fSource(source), fTrie(kSerializedUnitExtrasStemTrie) {}
|
||||
|
||||
Token nextToken(UErrorCode& status) {
|
||||
|
@ -547,6 +640,11 @@ private:
|
|||
return;
|
||||
}
|
||||
|
||||
if (!hasNext()) {
|
||||
// probably "one"
|
||||
return;
|
||||
}
|
||||
|
||||
// state:
|
||||
// 0 = no tokens seen yet (will accept power, SI prefix, or simple unit)
|
||||
// 1 = power token seen (will not accept another power token)
|
||||
|
@ -634,44 +732,22 @@ private:
|
|||
|
||||
|
||||
MeasureUnit MeasureUnit::forIdentifier(const char* identifier, UErrorCode& status) {
|
||||
UnitIdentifierParser parser = UnitIdentifierParser::from(identifier, status);
|
||||
if (U_FAILURE(status)) {
|
||||
// Unrecoverable error
|
||||
return MeasureUnit();
|
||||
}
|
||||
|
||||
CharString builder;
|
||||
while (parser.hasNext()) {
|
||||
CompoundUnit compoundUnit;
|
||||
parser.nextCompoundUnit(compoundUnit, status);
|
||||
if (U_FAILURE(status)) {
|
||||
// Invalid syntax
|
||||
return MeasureUnit();
|
||||
}
|
||||
if (builder.length() > 0) {
|
||||
builder.append('+', status);
|
||||
}
|
||||
compoundUnit.appendTo(builder, status);
|
||||
}
|
||||
|
||||
// Success
|
||||
return MeasureUnit(builder.cloneData(status));
|
||||
return Parser::from(identifier, status).getOnlySequenceUnit(status).build(status);
|
||||
}
|
||||
|
||||
UMeasureUnitComplexity MeasureUnit::getComplexity(UErrorCode& status) const {
|
||||
const char* id = getIdentifier();
|
||||
UnitIdentifierParser parser = UnitIdentifierParser::from(id, status);
|
||||
Parser parser = Parser::from(id, status);
|
||||
if (U_FAILURE(status)) {
|
||||
// Unrecoverable error
|
||||
return UMEASURE_UNIT_SINGLE;
|
||||
}
|
||||
|
||||
CompoundUnit compoundUnit;
|
||||
parser.nextCompoundUnit(compoundUnit, status);
|
||||
if (compoundUnit.isSingle()) {
|
||||
return UMEASURE_UNIT_SINGLE;
|
||||
} else if (parser.hasNext()) {
|
||||
if (parser.hasNext()) {
|
||||
return UMEASURE_UNIT_SEQUENCE;
|
||||
} else if (compoundUnit.isSingle()) {
|
||||
return UMEASURE_UNIT_SINGLE;
|
||||
} else {
|
||||
return UMEASURE_UNIT_COMPOUND;
|
||||
}
|
||||
|
@ -679,65 +755,44 @@ UMeasureUnitComplexity MeasureUnit::getComplexity(UErrorCode& status) const {
|
|||
|
||||
UMeasureSIPrefix MeasureUnit::getSIPrefix(UErrorCode& status) const {
|
||||
const char* id = getIdentifier();
|
||||
return UnitIdentifierParser::from(id, status).getOnlySingleUnit(status).siPrefix;
|
||||
return Parser::from(id, status).getOnlySingleUnit(status).siPrefix;
|
||||
}
|
||||
|
||||
MeasureUnit MeasureUnit::withSIPrefix(UMeasureSIPrefix prefix, UErrorCode& status) const {
|
||||
const char* id = getIdentifier();
|
||||
SingleUnit singleUnit = UnitIdentifierParser::from(id, status).getOnlySingleUnit(status);
|
||||
if (U_FAILURE(status)) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
SingleUnit singleUnit = Parser::from(id, status).getOnlySingleUnit(status);
|
||||
singleUnit.siPrefix = prefix;
|
||||
CharString builder;
|
||||
singleUnit.appendTo(builder, status);
|
||||
return MeasureUnit(builder.cloneData(status));
|
||||
return singleUnit.build(status);
|
||||
}
|
||||
|
||||
int8_t MeasureUnit::getPower(UErrorCode& status) const {
|
||||
const char* id = getIdentifier();
|
||||
return UnitIdentifierParser::from(id, status).getOnlySingleUnit(status).power;
|
||||
return Parser::from(id, status).getOnlySingleUnit(status).power;
|
||||
}
|
||||
|
||||
MeasureUnit MeasureUnit::withPower(int8_t power, UErrorCode& status) const {
|
||||
const char* id = getIdentifier();
|
||||
SingleUnit singleUnit = UnitIdentifierParser::from(id, status).getOnlySingleUnit(status);
|
||||
if (U_FAILURE(status)) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
CharString builder;
|
||||
SingleUnit singleUnit = Parser::from(id, status).getOnlySingleUnit(status);
|
||||
singleUnit.power = power;
|
||||
if (power < 0) {
|
||||
builder.append("one-per-", status);
|
||||
}
|
||||
singleUnit.appendTo(builder, status);
|
||||
return MeasureUnit(builder.cloneData(status));
|
||||
return singleUnit.build(status);
|
||||
}
|
||||
|
||||
MeasureUnit MeasureUnit::reciprocal(UErrorCode& status) const {
|
||||
const char* id = getIdentifier();
|
||||
CompoundUnit compoundUnit = UnitIdentifierParser::from(id, status).getOnlyCompoundUnit(status);
|
||||
if (U_FAILURE(status)) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
compoundUnit.reciprocal();
|
||||
CharString builder;
|
||||
compoundUnit.appendTo(builder, status);
|
||||
return MeasureUnit(builder.cloneData(status));
|
||||
CompoundUnit compoundUnit = Parser::from(id, status).getOnlyCompoundUnit(status);
|
||||
compoundUnit.takeReciprocal();
|
||||
return compoundUnit.build(status);
|
||||
}
|
||||
|
||||
MeasureUnit MeasureUnit::product(const MeasureUnit& other, UErrorCode& status) const {
|
||||
const char* id = getIdentifier();
|
||||
CompoundUnit compoundUnit = UnitIdentifierParser::from(id, status).getOnlyCompoundUnit(status);
|
||||
CompoundUnit compoundUnit = Parser::from(id, status).getOnlyCompoundUnit(status);
|
||||
if (U_FAILURE(status)) {
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Append other's first CompoundUnit to compoundUnit, then assert other has only one
|
||||
UnitIdentifierParser otherParser = UnitIdentifierParser::from(other.getIdentifier(), status);
|
||||
Parser otherParser = Parser::from(other.getIdentifier(), status);
|
||||
otherParser.nextCompoundUnit(compoundUnit, status);
|
||||
if (U_FAILURE(status)) {
|
||||
return *this;
|
||||
|
@ -747,16 +802,14 @@ MeasureUnit MeasureUnit::product(const MeasureUnit& other, UErrorCode& status) c
|
|||
return *this;
|
||||
}
|
||||
|
||||
CharString builder;
|
||||
compoundUnit.appendTo(builder, status);
|
||||
return MeasureUnit(builder.cloneData(status));
|
||||
return compoundUnit.build(status);
|
||||
}
|
||||
|
||||
LocalArray<MeasureUnit> MeasureUnit::getSingleUnits(UErrorCode& status) const {
|
||||
const char* id = getIdentifier();
|
||||
CompoundUnit compoundUnit = UnitIdentifierParser::from(id, status).getOnlyCompoundUnit(status);
|
||||
CompoundUnit compoundUnit = Parser::from(id, status).getOnlyCompoundUnit(status);
|
||||
if (U_FAILURE(status)) {
|
||||
return LocalArray<MeasureUnit>::withLength(nullptr, 0);
|
||||
return LocalArray<MeasureUnit>();
|
||||
}
|
||||
|
||||
const CompoundUnit::SingleUnitList& numerator = compoundUnit.getNumeratorUnits();
|
||||
|
@ -764,16 +817,30 @@ LocalArray<MeasureUnit> MeasureUnit::getSingleUnits(UErrorCode& status) const {
|
|||
int32_t count = numerator.length() + denominator.length();
|
||||
MeasureUnit* arr = new MeasureUnit[count];
|
||||
|
||||
CharString builder;
|
||||
int32_t i = 0;
|
||||
for (int32_t j = 0; j < numerator.length(); j++) {
|
||||
numerator[j]->appendTo(builder.clear(), status);
|
||||
arr[i++] = MeasureUnit(builder.cloneData(status));
|
||||
arr[i++] = numerator[j]->build(status);
|
||||
}
|
||||
for (int32_t j = 0; j < denominator.length(); j++) {
|
||||
builder.clear().append("one-per-", status);
|
||||
denominator[j]->appendTo(builder, status);
|
||||
arr[i++] = MeasureUnit(builder.cloneData(status));
|
||||
arr[i++] = denominator[j]->build(status);
|
||||
}
|
||||
|
||||
return LocalArray<MeasureUnit>::withLength(arr, count);
|
||||
}
|
||||
|
||||
LocalArray<MeasureUnit> MeasureUnit::getCompoundUnits(UErrorCode& status) const {
|
||||
const char* id = getIdentifier();
|
||||
SequenceUnit sequenceUnit = Parser::from(id, status).getOnlySequenceUnit(status);
|
||||
if (U_FAILURE(status)) {
|
||||
return LocalArray<MeasureUnit>();
|
||||
}
|
||||
|
||||
const SequenceUnit::CompoundUnitList& unitVector = sequenceUnit.getUnits();
|
||||
int32_t count = unitVector.length();
|
||||
MeasureUnit* arr = new MeasureUnit[count];
|
||||
|
||||
for (int32_t i = 0; i < count; i++) {
|
||||
arr[i] = unitVector[i]->build(status);
|
||||
}
|
||||
|
||||
return LocalArray<MeasureUnit>::withLength(arr, count);
|
||||
|
|
|
@ -79,6 +79,7 @@ private:
|
|||
void Test20332_PersonUnits();
|
||||
void TestNumericTime();
|
||||
void TestNumericTimeSomeSpecialFormats();
|
||||
void TestInvalidIdentifiers();
|
||||
void TestCompoundUnitOperations();
|
||||
void verifyFormat(
|
||||
const char *description,
|
||||
|
@ -149,6 +150,11 @@ private:
|
|||
const char* identifier,
|
||||
const char** subIdentifiers,
|
||||
int32_t subIdentifierCount);
|
||||
void verifySequenceUnit(
|
||||
const MeasureUnit& unit,
|
||||
const char* identifier,
|
||||
const char** subIdentifiers,
|
||||
int32_t subIdentifierCount);
|
||||
};
|
||||
|
||||
void MeasureFormatTest::runIndexedTest(
|
||||
|
@ -193,6 +199,7 @@ void MeasureFormatTest::runIndexedTest(
|
|||
TESTCASE_AUTO(Test20332_PersonUnits);
|
||||
TESTCASE_AUTO(TestNumericTime);
|
||||
TESTCASE_AUTO(TestNumericTimeSomeSpecialFormats);
|
||||
TESTCASE_AUTO(TestInvalidIdentifiers);
|
||||
TESTCASE_AUTO(TestCompoundUnitOperations);
|
||||
TESTCASE_AUTO_END;
|
||||
}
|
||||
|
@ -3227,6 +3234,34 @@ void MeasureFormatTest::TestNumericTimeSomeSpecialFormats() {
|
|||
verifyFormat("Danish fhoursFminutes", fmtDa, fhoursFminutes, 2, "2.03,877");
|
||||
}
|
||||
|
||||
void MeasureFormatTest::TestInvalidIdentifiers() {
|
||||
IcuTestErrorCode status(*this, "TestInvalidIdentifiers");
|
||||
|
||||
const char* const inputs[] = {
|
||||
"kilo",
|
||||
"kilokilo",
|
||||
"onekilo",
|
||||
"meterkilo",
|
||||
"meter-kilo",
|
||||
"k",
|
||||
"meter-",
|
||||
"meter+",
|
||||
"-meter",
|
||||
"+meter",
|
||||
"-kilometer",
|
||||
"+kilometer",
|
||||
"-p2-meter",
|
||||
"+p2-meter",
|
||||
"+",
|
||||
"-"
|
||||
};
|
||||
|
||||
for (const auto& input : inputs) {
|
||||
MeasureUnit::forIdentifier(input, status);
|
||||
status.expectErrorAndReset(U_ILLEGAL_ARGUMENT_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
void MeasureFormatTest::TestCompoundUnitOperations() {
|
||||
IcuTestErrorCode status(*this, "TestCompoundUnitOperations");
|
||||
|
||||
|
@ -3265,12 +3300,17 @@ void MeasureFormatTest::TestCompoundUnitOperations() {
|
|||
.product(kilometer, status)
|
||||
.product(kilometer, status)
|
||||
.reciprocal(status);
|
||||
MeasureUnit overQuarticKilometer4 = meter.withPower(4, status)
|
||||
.reciprocal(status)
|
||||
.withSIPrefix(UMEASURE_SI_PREFIX_KILO, status);
|
||||
|
||||
verifySingleUnit(overQuarticKilometer2, UMEASURE_SI_PREFIX_KILO, -4, "one-per-p4-kilometer");
|
||||
verifySingleUnit(overQuarticKilometer3, UMEASURE_SI_PREFIX_KILO, -4, "one-per-p4-kilometer");
|
||||
verifySingleUnit(overQuarticKilometer4, UMEASURE_SI_PREFIX_KILO, -4, "one-per-p4-kilometer");
|
||||
|
||||
assertTrue("reciprocal equality", overQuarticKilometer1 == overQuarticKilometer2);
|
||||
assertTrue("reciprocal equality", overQuarticKilometer1 == overQuarticKilometer3);
|
||||
assertTrue("reciprocal equality", overQuarticKilometer1 == overQuarticKilometer4);
|
||||
|
||||
MeasureUnit kiloSquareSecond = MeasureUnit::getSecond()
|
||||
.withPower(2, status).withSIPrefix(UMEASURE_SI_PREFIX_KILO, status);
|
||||
|
@ -3314,6 +3354,43 @@ void MeasureFormatTest::TestCompoundUnitOperations() {
|
|||
status.expectErrorAndReset(U_ILLEGAL_ARGUMENT_ERROR);
|
||||
meterSecond.withSIPrefix(UMEASURE_SI_PREFIX_CENTI, status);
|
||||
status.expectErrorAndReset(U_ILLEGAL_ARGUMENT_ERROR);
|
||||
|
||||
MeasureUnit footInch = MeasureUnit::forIdentifier("foot+inch", status);
|
||||
MeasureUnit inchFoot = MeasureUnit::forIdentifier("inch+foot", status);
|
||||
|
||||
const char* footInchSub[] = {"foot", "inch"};
|
||||
verifySequenceUnit(footInch, "foot+inch",
|
||||
footInchSub, UPRV_LENGTHOF(footInchSub));
|
||||
const char* inchFootSub[] = {"inch", "foot"};
|
||||
verifySequenceUnit(inchFoot, "inch+foot",
|
||||
inchFootSub, UPRV_LENGTHOF(inchFootSub));
|
||||
|
||||
assertTrue("order matters inequality", footInch != inchFoot);
|
||||
|
||||
// TODO(ICU-20920): Enable the one1 tests when the dimensionless base unit ID is updated
|
||||
// MeasureUnit one1;
|
||||
MeasureUnit one2 = MeasureUnit::forIdentifier("one", status);
|
||||
MeasureUnit one3 = MeasureUnit::forIdentifier("", status);
|
||||
MeasureUnit squareOne = one2.withPower(2, status);
|
||||
MeasureUnit onePerOne = one2.reciprocal(status);
|
||||
MeasureUnit squareKiloOne = squareOne.withSIPrefix(UMEASURE_SI_PREFIX_KILO, status);
|
||||
MeasureUnit onePerSquareKiloOne = squareKiloOne.reciprocal(status);
|
||||
MeasureUnit oneOne = MeasureUnit::forIdentifier("one-one", status);
|
||||
MeasureUnit onePlusOne = MeasureUnit::forIdentifier("one+one", status);
|
||||
|
||||
// verifySingleUnit(one1, UMEASURE_SI_PREFIX_ONE, 1, "one");
|
||||
verifySingleUnit(one2, UMEASURE_SI_PREFIX_ONE, 1, "one");
|
||||
verifySingleUnit(one3, UMEASURE_SI_PREFIX_ONE, 1, "one");
|
||||
verifySingleUnit(squareOne, UMEASURE_SI_PREFIX_ONE, 1, "one");
|
||||
verifySingleUnit(onePerOne, UMEASURE_SI_PREFIX_ONE, -1, "one-per-one");
|
||||
verifySingleUnit(squareKiloOne, UMEASURE_SI_PREFIX_ONE, 1, "one");
|
||||
verifySingleUnit(onePerSquareKiloOne, UMEASURE_SI_PREFIX_ONE, -1, "one-per-one");
|
||||
verifySingleUnit(oneOne, UMEASURE_SI_PREFIX_ONE, 1, "one");
|
||||
verifySingleUnit(onePlusOne, UMEASURE_SI_PREFIX_ONE, 1, "one");
|
||||
|
||||
// assertTrue("one equality", one1 == one2);
|
||||
assertTrue("one equality", one2 == one3);
|
||||
assertTrue("one-per-one equality", onePerOne == onePerSquareKiloOne);
|
||||
}
|
||||
|
||||
|
||||
|
@ -3447,6 +3524,35 @@ void MeasureFormatTest::verifyCompoundUnit(
|
|||
}
|
||||
}
|
||||
|
||||
void MeasureFormatTest::verifySequenceUnit(
|
||||
const MeasureUnit& unit,
|
||||
const char* identifier,
|
||||
const char** subIdentifiers,
|
||||
int32_t subIdentifierCount) {
|
||||
IcuTestErrorCode status(*this, "verifySequenceUnit");
|
||||
UnicodeString uid(identifier, -1, US_INV);
|
||||
assertEquals(uid + ": Identifier",
|
||||
identifier,
|
||||
unit.getIdentifier());
|
||||
status.errIfFailureAndReset("%s: Identifier", identifier);
|
||||
assertTrue(uid + ": Constructor",
|
||||
unit == MeasureUnit::forIdentifier(identifier, status));
|
||||
status.errIfFailureAndReset("%s: Constructor", identifier);
|
||||
assertEquals(uid + ": Complexity",
|
||||
UMEASURE_UNIT_SEQUENCE,
|
||||
unit.getComplexity(status));
|
||||
status.errIfFailureAndReset("%s: Complexity", identifier);
|
||||
|
||||
LocalArray<MeasureUnit> subUnits = unit.getCompoundUnits(status);
|
||||
assertEquals(uid + ": Length", subIdentifierCount, subUnits.length());
|
||||
for (int32_t i = 0;; i++) {
|
||||
if (i >= subIdentifierCount || i >= subUnits.length()) break;
|
||||
assertEquals(uid + ": Sub-unit #" + Int64ToUnicodeString(i),
|
||||
subIdentifiers[i],
|
||||
subUnits[i].getIdentifier());
|
||||
}
|
||||
}
|
||||
|
||||
extern IntlTest *createMeasureFormatTest() {
|
||||
return new MeasureFormatTest();
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue