- For primitives: malloc/free, not new/delete.
- Some cleanup.
- Failing test cases for getOutputUnit(), with comments as to where it
likely needs to be plumbed in.
// Copy constructor
Usage::Usage(const Usage &other) : fUsage(nullptr), fLength(other.fLength), fError(other.fError) {
if (other.fUsage != nullptr) {
- fUsage = new char[fLength + 1];
+ fUsage = (char*)uprv_malloc(fLength + 1);
uprv_strncpy(fUsage, other.fUsage, fLength+1);
}
}
Usage& Usage::operator=(const Usage& other) {
fLength = other.fLength;
if (other.fUsage != nullptr) {
- fUsage = new char[fLength + 1];
+ fUsage = (char*)uprv_malloc(fLength + 1);
uprv_strncpy(fUsage, other.fUsage, fLength+1);
}
fError = other.fError;
return *this;
}
-// Move constructor
+// Move constructor - can it be improved by taking over src's "this" instead of
+// copying contents? Swapping pointers makes sense for heap objects but not for
+// stack objects.
+// *this = std::move(src);
Usage::Usage(Usage &&src) U_NOEXCEPT : fUsage(src.fUsage), fLength(src.fLength), fError(src.fError) {
// Take ownership away from src if necessary
src.fUsage = nullptr;
// Move assignment operator
Usage& Usage::operator=(Usage&& src) U_NOEXCEPT {
+ if (this == &src) {
+ return *this;
+ }
if (fUsage != nullptr) {
- delete[] fUsage;
+ uprv_free(fUsage);
}
fUsage = src.fUsage;
fLength = src.fLength;
Usage::~Usage() {
if (fUsage != nullptr) {
- delete[] fUsage;
+ uprv_free(fUsage);
fUsage = nullptr;
}
}
void Usage::set(StringPiece value) {
if (fUsage != nullptr) {
// TODO: reuse if possible, rather than always delete?
- delete[] fUsage;
+ uprv_free(fUsage);
fUsage = nullptr;
}
fLength = value.length();
- fUsage = new char[fLength+1];
+ fUsage = (char*)uprv_malloc(fLength+1);
uprv_strncpy(fUsage, value.data(), fLength);
fUsage[fLength] = 0;
}
}
}
-StubUnitsRouter::StubUnitsRouter(MeasureUnit inputUnit, Locale locale,
- StringPiece usage, UErrorCode &status)
- : fRegion(locale.getCountry(), status) {
- if (usage.compare("road") != 0) {
- status = U_UNSUPPORTED_ERROR;
- }
- if (inputUnit != MeasureUnit::getMeter()) {
- status = U_UNSUPPORTED_ERROR;
- }
-}
-
MaybeStackVector<Measure> StubUnitsRouter::route(double quantity, UErrorCode &status) const {
MeasureUnit unit;
MaybeStackVector<Measure> result;
return move;
}
-// WIP/FIXME/CLEANUP: I've implemented a "Units" class, for the fMacros.usage
-// member. Delete this comment block if that's good - initially I tried
-// `LocalArray<char> usage;`, which is what this comment contains.
-//
-// It turned out that to have a LocalArray field in MacroProps, LocalArray would
-// need a copy assignment operator), so I abandoned it:
-
-// template<typename Derived>
-// Derived NumberFormatterSettings<Derived>::usage(const StringPiece usage) const& {
-// Derived copy(*this);
-// int32_t usageLen = usage.length();
-// char* newUsage = new char[usageLen+1]; // Do we need error handling for allocation failures?
-// uprv_strncpy(newUsage, usage.data(), usageLen);
-// newUsage[usageLen] = 0;
-// copy.fMacros.usage.adoptInstead(newUsage);
-// return copy;
-// }
-
-// template<typename Derived>
-// Derived NumberFormatterSettings<Derived>::usage(const StringPiece usage)&& {
-// Derived move(std::move(*this));
-// int32_t usageLen = usage.length();
-// char* newUsage = new char[usageLen+1]; // Do we need error handling for allocation failures?
-// uprv_strncpy(newUsage, usage.data(), usageLen);
-// newUsage[usageLen] = 0;
-// move.fMacros.usage.adoptInstead(newUsage);
-// return move;
-// }
-
template<typename Derived>
Derived NumberFormatterSettings<Derived>::padding(const Padder& padder) const& {
Derived copy(*this);
void LocalizedNumberFormatter::formatImpl(impl::UFormattedNumberData* results, UErrorCode& status) const {
if (computeCompiled(status)) {
+ // FIXME: results needs outputUnit too, consider how to add that - pass
+ // `results` to formatStatic() instead of just results->quantity and
+ // ->getStringRef()? :
fCompiled->format(results->quantity, results->getStringRef(), status);
} else {
+ // FIXME: results needs outputUnit too, consider how to add that - pass
+ // `results` to formatStatic() instead of just results->quantity and
+ // ->getStringRef()? :
NumberFormatterImpl::formatStatic(fMacros, results->quantity, results->getStringRef(), status);
}
if (U_FAILURE(status)) {
// Outer modifier (CLDR units and currency long names)
if (isCldrUnit) {
if (macros.usage.isSet()) {
- fLongNameMultiplexer.adoptInstead(
- LongNameMultiplexer::forMeasureUnits(
- macros.locale,
- fUsagePrefsHandler->getOutputUnits(),
- unitWidth,
- resolvePluralRules(macros.rules, macros.locale, status),
- chain,
- status));
+ fLongNameMultiplexer.adoptInstead(LongNameMultiplexer::forMeasureUnits(
+ macros.locale, fUsagePrefsHandler->getOutputUnits(), unitWidth,
+ resolvePluralRules(macros.rules, macros.locale, status), chain, status));
chain = fLongNameMultiplexer.getAlias();
} else {
fLongNameHandler.adoptInstead(LongNameHandler::forMeasureUnit(
- macros.locale,
- resolvedUnit, // WIP/FIXME: not known at this time for usage()!
- macros.perUnit, // WIP/FIXME: deal with COMPOUND and MIXED units?
- unitWidth, resolvePluralRules(macros.rules, macros.locale, status), chain, status));
+ macros.locale, resolvedUnit, macros.perUnit, unitWidth,
+ resolvePluralRules(macros.rules, macros.locale, status), chain, status));
chain = fLongNameHandler.getAlias();
}
} else if (isCurrency && unitWidth == UNUM_UNIT_WIDTH_FULL_NAME) {
U_ASSERT(units.length() > 0);
result->fMeasureUnits.adoptInstead(new MeasureUnit[units.length()]);
for (int32_t i = 0, length = units.length(); i < length; i++) {
- result->fLongNameHandlers.adoptBack(
- LongNameHandler::forMeasureUnit(
- loc, *units[i],
- MeasureUnit(), // TODO(units): deal with COMPOUND and MIXED units
- width, rules, NULL, status),
- status);
+ auto *lnh = LongNameHandler::forMeasureUnit(
+ loc, *units[i],
+ MeasureUnit(), // TODO(units): deal with COMPOUND and MIXED units
+ width, rules, NULL, status);
+ if (U_FAILURE(status)) {
+ delete result;
+ return nullptr;
+ }
+ result->fLongNameHandlers.emplaceBack(std::move(*lnh));
result->fMeasureUnits[i] = *units[i];
}
return result;
private:
SimpleModifier fModifiers[StandardPlural::Form::COUNT];
+ // Not owned
const PluralRules *rules;
+ // Not owned
const MicroPropsGenerator *parent;
LongNameHandler(const PluralRules *rules, const MicroPropsGenerator *parent)
* this function can be used only once, because the base MicroProps instance
* will be modified and thus not be available for re-use.
*
+ * FIXME: document how the quantity passed in can be mutated by the chain of microprops' processQuantity methods.
+ *
* @param quantity The quantity for consideration and optional mutation.
* @param micros The MicroProps instance to populate. If this parameter is
* not already `*this`, it will be overwritten with a copy of `*this`.
*/
- void processQuantity(DecimalQuantity&, MicroProps& micros, UErrorCode& status) const U_OVERRIDE {
+ void processQuantity(DecimalQuantity &quantity, MicroProps µs,
+ UErrorCode &status) const U_OVERRIDE {
(void) status;
if (this == µs) {
// Unsafe path: no need to perform a copy.
if (U_FAILURE(status)) { return; }
U_ASSERT(idx >= 0); // Failures should have been taken care of by `status`.
const UnitPreferenceMetadata *m = metadata_[idx];
- outPreferences = unitPrefs_.getConstAlias() + m->prefsOffset;
+ outPreferences = unitPrefs_.getAlias() + m->prefsOffset;
preferenceCount = m->prefsCount;
}
U_NAMESPACE_BEGIN
-class U_I18N_API StubUnitsRouter {
+class U_I18N_API StubUnitsRouter : public UMemory {
public:
// As found in UnitsRouter
StubUnitsRouter(MeasureUnit inputUnit, StringPiece region, StringPiece usage,
UErrorCode &status);
- // TODO(units): consider this possible improvement for the constructor:
- // passing "Locale" instead of "StringPiece region"? :
- StubUnitsRouter(MeasureUnit inputUnit, Locale locale, StringPiece usage, UErrorCode &status);
-
// TODO(units): API under reconsideration: going via Measure may be
// excessive when we need a double; MaybeStackVector<Measure> might also not
// be what we want for dealing with Mixed, given that a MeasureUnit can, on
number_representation format formatted_value_sbimpl
# PluralRules internals:
unifiedcache
+ # Unit Formatting
+ units
group: numberformatter
# ICU 60+ NumberFormatter API
LocalizedNumberFormatter formatter = unloc_formatter.locale("en-ZA");
FormattedNumber formattedNum = formatter.formatDouble(300, status);
- assertEquals("unitUsage() road", "300 m", formattedNum.toString(status));
+ assertTrue("unitUsage() en-ZA road outputUnit",
+ MeasureUnit::getMeter() == formattedNum.getOutputUnit(status));
+ assertEquals("unitUsage() en-ZA road", "300 m", formattedNum.toString(status));
formatter = unloc_formatter.locale("en-GB");
formattedNum = formatter.formatDouble(300, status);
- assertEquals("unitUsage() road", "328 yd", formattedNum.toString(status));
+ assertTrue("unitUsage() en-GB road outputUnit",
+ MeasureUnit::getYard() == formattedNum.getOutputUnit(status));
+ assertEquals("unitUsage() en-GB road", "328 yd", formattedNum.toString(status));
formatter = unloc_formatter.locale("en-US");
formattedNum = formatter.formatDouble(300, status);
- assertEquals("unitUsage() road", "984 ft", formattedNum.toString(status));
+ assertTrue("unitUsage() en-US road outputUnit",
+ MeasureUnit::getFoot() == formattedNum.getOutputUnit(status));
+ assertEquals("unitUsage() en-US road", "984 ft", formattedNum.toString(status));
// TODO(hugovdm): consider fixing TODO(ICU-20941) too?
}