MeasureUnit::MeasureUnit(int32_t typeId, int32_t subTypeId)
: fId(nullptr), fSubTypeId(subTypeId), fTypeId(typeId) {
- fCurrency[0] = 0;
}
-MeasureUnit::MeasureUnit(const MeasureUnit &other) {
+MeasureUnit::MeasureUnit(const MeasureUnit &other)
+ : fId(nullptr) {
*this = other;
}
: fId(other.fId),
fSubTypeId(other.fSubTypeId),
fTypeId(other.fTypeId) {
- uprv_strcpy(fCurrency, other.fCurrency);
other.fId = nullptr;
}
if (this == &other) {
return *this;
}
+ uprv_free(fId);
if (other.fId) {
- auto* id = static_cast<char*>(uprv_malloc(uprv_strlen(other.fId) + 1));
- if (!id) {
+ fId = uprv_strdup(other.fId);
+ if (!fId) {
// Unrecoverable allocation error; set to the default unit
*this = MeasureUnit();
return *this;
}
- uprv_strcpy(id, other.fId);
- fId = id;
} else {
fId = nullptr;
}
fTypeId = other.fTypeId;
fSubTypeId = other.fSubTypeId;
- uprv_strcpy(fCurrency, other.fCurrency);
return *this;
}
if (this == &other) {
return *this;
}
+ uprv_free(fId);
fId = other.fId;
other.fId = nullptr;
fTypeId = other.fTypeId;
fSubTypeId = other.fSubTypeId;
- uprv_strcpy(fCurrency, other.fCurrency);
return *this;
}
}
MeasureUnit::~MeasureUnit() {
- uprv_free(const_cast<char*>(fId));
+ uprv_free(fId);
fId = nullptr;
}
const char *MeasureUnit::getType() const {
+ // We have a type & subtype only if fTypeId is present.
+ if (fTypeId == -1) {
+ return "";
+ }
return gTypes[fTypeId];
}
const char *MeasureUnit::getSubtype() const {
- return fCurrency[0] == 0 ? gSubTypes[getOffset()] : fCurrency;
+ // We have a type & subtype only if fTypeId is present.
+ if (fTypeId == -1) {
+ return "";
+ }
+ return toString();
}
const char *MeasureUnit::toString() const {
- return fId ? fId : getSubtype();
+ return fId ? fId : gSubTypes[getOffset()];
}
UBool MeasureUnit::operator==(const UObject& other) const {
const MeasureUnit &unit, const MeasureUnit &perUnit, bool* isResolved) {
int32_t unitOffset = unit.getOffset();
int32_t perUnitOffset = perUnit.getOffset();
+ if (unitOffset == -1 || perUnitOffset == -1) {
+ *isResolved = false;
+ return MeasureUnit();
+ }
// binary search for (unitOffset, perUnitOffset)
int32_t start = 0;
fTypeId = result;
result = binarySearch(
gSubTypes, gOffsets[fTypeId], gOffsets[fTypeId + 1], isoCurrency);
- if (result != -1) {
- fSubTypeId = result - gOffsets[fTypeId];
- } else {
- uprv_strncpy(fCurrency, isoCurrency, UPRV_LENGTHOF(fCurrency));
- fCurrency[3] = 0;
+ if (result == -1) {
+ fId = uprv_strdup(isoCurrency);
+ if (fId) {
+ fSubTypeId = -1;
+ return;
+ }
+ // malloc error: fall back to the undefined currency
+ result = binarySearch(
+ gSubTypes, gOffsets[fTypeId], gOffsets[fTypeId + 1], "XXX");
+ U_ASSERT(result != -1);
}
+ fSubTypeId = result - gOffsets[fTypeId];
}
void MeasureUnit::initNoUnit(const char *subtype) {
void MeasureUnit::setTo(int32_t typeId, int32_t subTypeId) {
fTypeId = typeId;
fSubTypeId = subTypeId;
- fCurrency[0] = 0;
+ uprv_free(fId);
+ fId = nullptr;
}
int32_t MeasureUnit::getOffset() const {
+ if (fTypeId < 0 || fSubTypeId < 0) {
+ return -1;
+ }
return gOffsets[fTypeId] + fSubTypeId;
}
static const UChar BAD2[] = u"??A";
static const UChar XXX[] = u"XXX";
static const char XXX8[] = "XXX";
+ static const UChar XYZ[] = u"XYZ";
+ static const char XYZ8[] = "XYZ";
static const UChar INV[] = u"{$%";
static const char INV8[] = "{$%";
static const UChar ZZZ[] = u"zz";
CurrencyUnit cu(USD, ec);
assertSuccess("CurrencyUnit", ec);
-
assertEquals("getISOCurrency()", USD, cu.getISOCurrency());
assertEquals("getSubtype()", USD8, cu.getSubtype());
+ // Test XYZ, a valid but non-standard currency.
+ // Note: Country code XY is private-use, so XYZ should remain unallocated.
+ CurrencyUnit extended(XYZ, ec);
+ assertSuccess("non-standard", ec);
+ assertEquals("non-standard", XYZ, extended.getISOCurrency());
+ assertEquals("non-standard", XYZ8, extended.getSubtype());
+
CurrencyUnit inv(INV, ec);
assertEquals("non-invariant", U_INVARIANT_CONVERSION_ERROR, ec);
assertEquals("non-invariant", XXX, inv.getISOCurrency());
// Test slicing
MeasureUnit sliced1 = cu;
MeasureUnit sliced2 = cu;
+ MeasureUnit sliced3 = extended;
assertEquals("Subtype after slicing 1", USD8, sliced1.getSubtype());
assertEquals("Subtype after slicing 2", USD8, sliced2.getSubtype());
+ assertEquals("Subtype after slicing 3", XYZ8, sliced3.getSubtype());
CurrencyUnit restored1(sliced1, ec);
CurrencyUnit restored2(sliced2, ec);
+ CurrencyUnit restored3(sliced3, ec);
assertSuccess("Restoring from MeasureUnit", ec);
assertEquals("Subtype after restoring 1", USD8, restored1.getSubtype());
assertEquals("Subtype after restoring 2", USD8, restored2.getSubtype());
+ assertEquals("Subtype after restoring 3", XYZ8, restored3.getSubtype());
assertEquals("ISO Code after restoring 1", USD, restored1.getISOCurrency());
assertEquals("ISO Code after restoring 2", USD, restored2.getISOCurrency());
+ assertEquals("ISO Code after restoring 3", XYZ, restored3.getISOCurrency());
// Test copy constructor failure
LocalPointer<MeasureUnit> meter(MeasureUnit::createMeter(ec));