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()? :
+ // TODO(units,hugovdm): results needs outputUnit too, consider how to
+ // add that - maybe 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()? :
+ // TODO(units,hugovdm): results needs outputUnit too, consider how to
+ // add that - maybe pass `results` to formatStatic() instead of just
+ // results->quantity and ->getStringRef()? :
NumberFormatterImpl::formatStatic(fMacros, results->quantity, results->getStringRef(), status);
}
if (U_FAILURE(status)) {
// The "unsafe" method simply re-uses fMicros, eliminating the extra copy operation.
// See MicroProps::processQuantity() for details.
-int32_t NumberFormatterImpl::format(DecimalQuantity& inValue, FormattedStringBuilder& outString,
- UErrorCode& status) const {
+int32_t NumberFormatterImpl::format(DecimalQuantity &inValue, FormattedStringBuilder &outString,
+ UErrorCode &status) const {
MicroProps micros;
preProcess(inValue, micros, status);
if (U_FAILURE(status)) { return 0; }
+ // TODO(units,hugovdm): micros.outputUnit contains the unit we wish to
+ // return via FormattedNumber::getOutputUnit(). Plumb it into the pipeline
+ // in a reasonable way.
int32_t length = writeNumber(micros, inValue, outString, 0, status);
length += writeAffixes(micros, outString, 0, length, status);
return length;
/////////////////////////////////////////////////////////////////////////////////////
// Unit Preferences and Conversions as our first step
- MeasureUnit resolvedUnit;
if (macros.usage.isSet()) {
if (!isCldrUnit) {
// We only support "usage" when the input unit is a CLDR Unit.
}
fUsagePrefsHandler.adoptInstead(usagePrefsHandler);
chain = fUsagePrefsHandler.getAlias();
- // TODO(units): this doesn't handle mixed units yet, caring only about
- // the first output unit:
- resolvedUnit = *(*usagePrefsHandler->getOutputUnits())[0];
- } else {
- resolvedUnit = macros.unit;
}
// Multiplier
chain = fLongNameMultiplexer.getAlias();
} else {
fLongNameHandler.adoptInstead(LongNameHandler::forMeasureUnit(
- macros.locale, resolvedUnit, macros.perUnit, unitWidth,
+ macros.locale, macros.unit, macros.perUnit, unitWidth,
resolvePluralRules(macros.rules, macros.locale, status), chain, status));
chain = fLongNameHandler.getAlias();
}
int32_t end, UErrorCode& status);
private:
- // Head of the MicroPropsGenerator linked list:
- // WIP/TODO(hugovdm): comprehend/document how this linked list functions
- // (and how it related to fMicros).
- // This points at the *end* of a chain of fMicroPropsGenerator. Subclasses' processQuantity methods
- // typically do a depth-first traversal of the linked list.
+ // Head of the MicroPropsGenerator linked list. Subclasses' processQuantity
+ // methods process this list in a parent-first order, such that the last
+ // item added, which this points to, typically has its logic executed last.
const MicroPropsGenerator *fMicroPropsGenerator = nullptr;
// Tail of the list:
// Other fields possibly used by the number formatting pipeline:
// TODO: Convert more of these LocalPointers to value objects to reduce the number of news?
- // TODO(units): what belongs in MicroProps::helpers? (e.g.
- // considering MicroProps::helpers::usageprefs.)
LocalPointer<const UsagePrefsHandler> fUsagePrefsHandler;
LocalPointer<const DecimalFormatSymbols> fSymbols;
LocalPointer<const PluralRules> fRules;
// Call the correct LongNameHandler based on outputUnit
for (int i = 0; i < fLongNameHandlers.length(); i++) {
- if (fMeasureUnits[i] == micros.helpers.outputUnit) {
+ if (fMeasureUnits[i] == micros.outputUnit) {
fLongNameHandlers[i]->processQuantity(quantity, micros, status);
return;
}
EmptyModifier emptyWeakModifier{false};
EmptyModifier emptyStrongModifier{true};
MultiplierFormatHandler multiplier;
- // TODO(units): In number_microprops.h there is a TODO(units) wondering
- // about having something here, instead of
- // NumberFormatterImpl::fUsagePrefs - e.g.:
- // UsagePrefsHandler usageprefs;
-
- // TODO(units/review): is this appropriate use of microprops? Changing this every
- // time we format a number - consider thread-safety? Unique microprops instance per
- // format() invocation?
- MeasureUnit outputUnit;
} helpers;
+ // TODO(units/review): move up / outside of the helpers struct.
+ // Consider thread-safety? Re-use of microprops instance?
+ //
+ // The MeasureUnit with which the output measurement is represented.
+ MeasureUnit outputUnit;
MicroProps() = default;
* 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.
+ * TODO(units,hugovdm): deal with outputUnits: processQuantity may need to
+ * return a MeasurementUnit instance too, in some fashion. Or do we just
+ * keep it in micros.outputUnit?
*
* @param quantity The quantity for consideration and optional mutation.
* @param micros The MicroProps instance to populate. If this parameter is
#define UPRV_NOARG
-// FIXME/TODO: see if there's Unit Usage Formatting consequences here? (Need to
-// place rounding etc in the right place.)
+// TODO(units,hugovdm): see if there's Unit Usage Formatting consequences here?
+// Ensure tests are thorough, check rounding etc.
void FormattedNumber::toDecimalNumber(ByteSink& sink, UErrorCode& status) const {
UPRV_FORMATTED_VALUE_METHOD_GUARD(UPRV_NOARG)
impl::DecNum decnum;
fData->getAllFieldPositions(fpih, status);
}
-// WIP/TODO(hugovdm): official public API.
+// TODO(units,hugovdm): properly implement and test this official public API.
MeasureUnit FormattedNumber::getOutputUnit(UErrorCode& status) const {
UPRV_FORMATTED_VALUE_METHOD_GUARD(MeasureUnit())
return fData->outputUnit;
/**
- * macrosToMicroGenerator produces MicroPropsGenerator, which produces
- * MicroProps. Chain of MicroProps, which inherit from MicroPropsGenerators.
- *
* This interface is used when all number formatting settings, including the locale, are known, except for the quantity
* itself. The {@link #processQuantity} method performs the final step in the number processing pipeline: it uses the
* quantity to generate a finalized {@link MicroProps}, which can be used to render the number to output.
: fUnitsRouter(inputUnit, StringPiece(locale.getCountry()), usage, status),
fParent(parent) {
}
-// Is this not better? :
-// : fUnitsRouter(inputUnit, locale, usage, status), fParent(parent) {}
void UsagePrefsHandler::processQuantity(DecimalQuantity &quantity, MicroProps µs,
UErrorCode &status) const {
quantity.roundToInfinity(); // Enables toDouble
auto routed = fUnitsRouter.route(quantity.toDouble(), status);
- micros.helpers.outputUnit = routed[0]->getUnit();
+ micros.outputUnit = routed[0]->getUnit();
quantity.setToDouble(routed[0]->getNumber().getDouble());
// TODO(units): here we are always overriding Precision. (1) get precision
/**
* Returns the list of possible output units, i.e. the full set of
* preferences, for the localized, usage-specific unit preferences.
+ *
+ * The returned pointer should be valid for the lifetime of the
+ * UsagePrefsHandler instance.
*/
const MaybeStackVector<MeasureUnit> *getOutputUnits() const {
return fUnitsRouter.getOutputUnits();
DecimalQuantity quantity;
// The output unit for the formatted quantity.
+ // TODO(units,hugovdm): populate this correctly - it's not properly
+ // implemented yet.
MeasureUnit outputUnit;
};
/** @internal */
Usage usage; // = Usage(); (no usage)
- //
- // WIP/TODO(hugovdm,review): I tried `LocalArray<char>` instead of creating
- // the Usage class, but it's lacking a copy assignment operator:
- //
- // error: object of type 'icu_67::number::impl::MacroProps' cannot be assigned because its copy assignment operator is implicitly deleted
- // ./unicode/numberformatter.h:1413:22: note: copy assignment operator of 'MacroProps' is implicitly deleted because field 'usage' has a deleted copy assignment operator
- // ../common/unicode/localpointer.h:399:5: note: copy assignment operator is implicitly deleted because 'LocalArray<char>' has a user-declared move constructor
/** @internal */
const AffixPatternProvider* affixProvider = nullptr; // no ownership
* @return The fluent chain.
* @draft ICU 68
*/
- Derived usage(const StringPiece usage) const &;
+ Derived usage(StringPiece usage) const &;
/**
* Overload of usage() for use on an rvalue reference.
* @return The fluent chain.
* @draft ICU 68
*/
- Derived usage(const StringPiece usage) &&;
+ Derived usage(StringPiece usage) &&;
#endif // U_HIDE_DRAFT_API
#ifndef U_HIDE_INTERNAL_API
MaybeStackVector<Measure> route(double quantity, UErrorCode &status) const;
+ /**
+ * Returns the list of possible output units, i.e. the full set of
+ * preferences, for the localized, usage-specific unit preferences.
+ *
+ * The returned pointer should be valid for the lifetime of the
+ * UnitsRouter instance.
+ */
const MaybeStackVector<MeasureUnit> *getOutputUnits() const;
private:
+ // List of possible output units
MaybeStackVector<MeasureUnit> outputUnits_;
+
MaybeStackVector<ConverterPreference> converterPreferences_;
};
LocalizedNumberFormatter formatter = unloc_formatter.locale("en-ZA");
FormattedNumber formattedNum = formatter.formatDouble(300, status);
- assertTrue("unitUsage() en-ZA road outputUnit",
- MeasureUnit::getMeter() == formattedNum.getOutputUnit(status));
+ // TODO(units,hugovdm): implement FormattedNumber::getOutputUnit()
+// 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);
- assertTrue("unitUsage() en-GB road outputUnit",
- MeasureUnit::getYard() == formattedNum.getOutputUnit(status));
+ // TODO(units,hugovdm): implement FormattedNumber::getOutputUnit()
+// 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);
- assertTrue("unitUsage() en-US road outputUnit",
- MeasureUnit::getFoot() == formattedNum.getOutputUnit(status));
+ // TODO(units,hugovdm): implement FormattedNumber::getOutputUnit()
+// 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?