/////////////////////////////////////////////////////////
+// TODO(units): the StubUnitsRouter should be deleted soon, as we switch to
+// using the proper UnitsRouter - so it's just temporarily hanging out in
+// number_fluent.cpp
StubUnitsRouter::StubUnitsRouter(MeasureUnit inputUnit, StringPiece region,
StringPiece usage, UErrorCode &status)
: fRegion(region, status) {
}
MaybeStackVector<MeasureUnit> StubUnitsRouter::getOutputUnits() const {
- // fprintf(stderr, "======\nLocale: %s\n-------", fStubLocale.getName());
MaybeStackVector<MeasureUnit> result;
- // fprintf(stderr, "======\n%s\n%s\n-------", fStubLocale.getCountry(), "GB");
- // fprintf(stderr, "======\n%d\n%d\n-------", fStubLocale.getCountry()[2], "GB"[2]);
if (uprv_strcmp(fRegion.data(), "GB") == 0) {
result.emplaceBack(MeasureUnit::getMile());
result.emplaceBack(MeasureUnit::getYard());
return move;
}
-// WIP/FIXME/CLEANUP: My attempt at `LocalArray<char> usage;` looked like this
-// (but to have a LocalArray field in MacroProps, LocalArray would need a copy
-// assignment operator):
+// 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& {
return nullptr;
}
- MeasureUnit resolvedUnit;
- // WIP/FIXME: UnitRouter preparation/calculations here?
- // if (macros.usage.length() > 0) {
- // fUnitsRouter.adoptInstead(
- // new StubUnitsRouter(macros.unit, macros.locale, macros.usage.fUsage, status));
- // if (U_FAILURE(status)) { return nullptr; }
- // // FIXME/WIP/TODO(hugovdm): unit depends on quantity, so we can't really
- // // grab this now - we need to grab it at formatDouble time.
- // resolvedUnit = fUnitsRouter->getOutputUnit();
- // } else {
- // resolvedUnit = macros.unit;
- // }
-
/////////////////////////////////////////////////////////////////////////////////////
/// START POPULATING THE DEFAULT MICROPROPS AND BUILDING THE MICROPROPS GENERATOR ///
/////////////////////////////////////////////////////////////////////////////////////
// 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();
- // FIXME:
+ // TODO(units): this doesn't handle mixed units yet, caring only about
+ // the first output unit:
resolvedUnit = *usagePrefsHandler->getOutputUnits()[0];
} else {
resolvedUnit = macros.unit;
// Other fields possibly used by the number formatting pipeline:
// TODO: Convert more of these LocalPointers to value objects to reduce the number of news?
- // vs MicroProps::helpers::usageprefs?
+ // 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;
LocalPointer<ImmutablePatternModifier> fImmutablePatternModifier;
LocalPointer<const LongNameHandler> fLongNameHandler;
LocalPointer<const LongNameMultiplexer> fLongNameMultiplexer;
- LocalArray<const MeasureUnit> fMeasureUnitArray; // WIP/TODO(hugovdm): list of possible units?
- LocalArray<const LongNameHandler> fLongNameHandlerArray; // WIP/TODO(hugovdm): corresponding list of long name handlers?
- // LocalPointer<const StubUnitsRouter> fUnitsRouter; // WIP/TODO(hugovdm): the eventual units router instance.
LocalPointer<const CompactHandler> fCompactHandler;
// Value objects possibly used by the number formatting pipeline:
return nullptr;
}
U_ASSERT(units.length() > 0);
- // result->fLongNameHandlers.adoptInstead(new LongNameHandler *[units.length()]);
result->fMeasureUnits.adoptInstead(new MeasureUnit[units.length()]);
- // result->fParent = parent;
for (int32_t i = 0, length = units.length(); i < length; i++) {
- // U_ASSERT(i < MAX_PREFS_COUNT); // FIXME: enforce by unit tests on preferences!
- // FIXME: stop using fixed-size fLongNameHandlers array. But how to do
- // that best? MaybeStackVector doesn't let us insert pointers created.
result->fLongNameHandlers.adoptBack(
LongNameHandler::forMeasureUnit(
loc, *units[i],
- MeasureUnit(), // WIP/FIXME: deal with COMPOUND and MIXED units?
+ MeasureUnit(), // TODO(units): deal with COMPOUND and MIXED units
width, rules, NULL, status),
status);
result->fMeasureUnits[i] = *units[i];
// letting LongNameHandler handle it: we don't know which LongNameHandler to
// call until we've called the parent!
fParent->processQuantity(quantity, micros, status);
- // fprintf(stderr, "Looking for %s\n", micros.helpers.outputUnit.getIdentifier());
- // FIXME: pick the correct one based on unit:
+ // Call the correct LongNameHandler based on outputUnit
for (int i = 0; i < fLongNameHandlers.length(); i++) {
if (fMeasureUnits[i] == micros.helpers.outputUnit) {
- // fprintf(stderr, "%s == %s\n", fMeasureUnits[i].getIdentifier(), micros.helpers.outputUnit.getIdentifier());
fLongNameHandlers[i]->processQuantity(quantity, micros, status);
return;
- // } else {
- // fprintf(stderr, "%s != %s\n", fMeasureUnits[i].getIdentifier(), micros.helpers.outputUnit.getIdentifier());
}
}
- status = U_RESOURCE_TYPE_MISMATCH; // FIXME: failure type? Assert failure even.
+ status = U_RESOURCE_TYPE_MISMATCH; // TODO(units): do we want new failure types? Or maybe an assert
+ // failure even?
}
#endif /* #if !UCONFIG_NO_FORMATTING */
U_NAMESPACE_BEGIN namespace number {
namespace impl {
-// FIXME: describe me?
class LongNameHandler : public MicroPropsGenerator, public ModifierStore, public UMemory {
public:
static UnicodeString getUnitDisplayName(
const UNumberUnitWidth &width, const PluralRules *rules,
const MicroPropsGenerator *parent, UErrorCode &status);
- // FIXME: describe me?
void simpleFormatsToModifiers(const UnicodeString *simpleFormats, Field field, UErrorCode &status);
void multiSimpleFormatsToModifiers(const UnicodeString *leadFormats, UnicodeString trailFormat,
Field field, UErrorCode &status);
const int MAX_PREFS_COUNT = 10;
-/// FIXME
-/// And check if ModifierStore is the right pattern here.
+/**
+ * A MicroPropsGenerator that multiplexes between different LongNameHandlers,
+ * depending on the outputUnit (micros.helpers.outputUnit should be set earlier
+ * in the chain).
+ */
class LongNameMultiplexer : public MicroPropsGenerator, public UMemory {
public:
static LongNameMultiplexer *forMeasureUnits(const Locale &loc,
UErrorCode &status) const U_OVERRIDE;
private:
- // LocalPointer<const LongNameHandler> fLongNameHandlers[MAX_PREFS_COUNT];
+ /**
+ * Because we only know which LongNameHandler we wish to call after calling
+ * earlier MicroPropsGenerators in the chain, LongNameMultiplexer keeps the
+ * parent link, while the LongNameHandlers are given no parents.
+ */
MaybeStackVector<const LongNameHandler> fLongNameHandlers;
LocalArray<MeasureUnit> fMeasureUnits;
const MicroPropsGenerator *fParent;
LongNameMultiplexer(const MicroPropsGenerator *parent) : fParent(parent) {
- // // LocalPointer related:
- // // U_ASSERT(fLongNameHandlers[0] == NULL);
- // // U_ASSERT(fLongNameHandlers[MAX_PREFS_COUNT-1] == NULL);
}
};
U_NAMESPACE_BEGIN namespace number {
namespace impl {
-// WIP/FIXME: Generated by MicroPropsGenerator, but inherits from it too?
-// Document why?
-//
-// Do we need any new Units Usage related thing here? Private / runtime
-// properties. Used for evaluation in code. MicroPropsGenerator is the builder.
+// TODO(units): generated by MicroPropsGenerator, but inherits from it too. Do
+// we want to better document why? There's an explanation for processQuantity:
+// * As MicroProps is the "base instance", this implementation of
+// * MicoPropsGenerator::processQuantity() just ensures that the output
+// * `micros` is correctly initialized.
struct MicroProps : public MicroPropsGenerator {
// NOTE: All of these fields are properly initialized in NumberFormatterImpl.
EmptyModifier emptyWeakModifier{false};
EmptyModifier emptyStrongModifier{true};
MultiplierFormatHandler multiplier;
- // UsagePrefsHandler usageprefs; // vs
- // NumberFormatterImpl::fUsagePrefs?
+ // TODO(units): In number_microprops.h there is a TODO(units) wondering
+ // about having something here, instead of
+ // NumberFormatterImpl::fUsagePrefs - e.g.:
+ // UsagePrefsHandler usageprefs;
- // FIXME: is this appropriate use of microprops? Changing this every
- // time we format a number - thread-safe? Unique microprops instance per
+ // 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;
MicroProps& operator=(const MicroProps& other) = default;
- // WIP/FIXME: document this?
- // This is used in subclasses to call the chain of MicroPropsGenerators.
- // micros
/**
* As MicroProps is the "base instance", this implementation of
* MicoPropsGenerator::processQuantity() just ensures that the output
private:
// Internal fields:
- // FIXME: describe.
+ // FIXME: describe?
bool exhausted = false;
};
}
private:
+ // TODO(units): use UnitsRouter, throw away StubUnitsRouter.
StubUnitsRouter fUnitsRouter;
const MicroPropsGenerator *fParent;
};
/** @internal */
Usage usage; // = Usage(); (no usage)
//
- // WIP/FYI: I tried `LocalArray<char>`, but it's lacking a copy assignment operator:
+ // 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
*
* If a per-unit is specified without a primary unit via {@link #unit}, the behavior is undefined.
*
- * WIP/TODO(hugovdm): how does this deal with COMPOUND and MIXED units?
- * Specify and test!
+ * TODO(units): add proper support for COMPOUND and MIXED units.
+ * Specify behaviour here, test intended behaviour...
*
* @param perUnit
* The unit to render in the denominator.
/**
* Overload of perUnit() for use on an rvalue reference.
*
- * WIP/TODO(hugovdm): how does this deal with COMPOUND and MIXED units?
- * Specify and test!
+ * TODO(units): add proper support for COMPOUND and MIXED units.
+ * Specify behaviour here, test intended behaviour...
*
* @param perUnit
* The unit to render in the denominator.
*
* Note: consider using the MeasureFormat factory methods that return by value.
*
- * WIP/TODO(hugovdm): how does this deal with COMPOUND and MIXED units?
- * Specify and test!
+ * TODO(units): add proper support for COMPOUND and MIXED units.
+ * Specify behaviour here, test intended behaviour...
*
* @param perUnit
* The unit to render in the denominator.
/**
* Overload of adoptPerUnit() for use on an rvalue reference.
*
- * WIP/TODO(hugovdm): how does this deal with COMPOUND and MIXED units?
- * Specify and test!
+ * TODO(units): add proper support for COMPOUND and MIXED units.
+ * Specify behaviour here, test intended behaviour...
*
* @param perUnit
* The unit to render in the denominator.
// © 2020 and later: Unicode, Inc. and others.
// License & terms of use: http://www.unicode.org/copyright.html
-// As a temporary stubbed out version, I've not given it its own .cpp file: I
-// let the code tresspass in number_fluent.cpp.
+// TODO(units): delete this file! Use the proper UnitsRouter instead. Since this
+// is a temporary stubbed out version, I've not given it its own .cpp file: the
+// actual code is tresspassing in number_fluent.cpp.
// #include "unicode/utypes.h"
U_NAMESPACE_BEGIN
-/**
- * Contains the complex unit converter and the limit which representing the smallest value that the
- * converter should accept. For example, if the converter is converting to `foot+inch` and the limit
- * equals 3.0, thus means the converter should not convert to a value less than `3.0 feet`.
- *
- * NOTE:
- * if the limit doest not has a value `i.e. (std::numeric_limits<double>::lowest())`, this mean there
- * is no limit for the converter.
- */
-/* struct ConverterPreference : UMemory { */
-/* ComplexUnitsConverter converter; */
-/* double limit; */
-
-/* ConverterPreference(MeasureUnit source, MeasureUnit complexTarget, double limit, */
-/* const ConversionRates &ratesInfo, UErrorCode &status) */
-/* : converter(source, complexTarget, ratesInfo, status), limit(limit) {} */
-
-/* ConverterPreference(MeasureUnit source, MeasureUnit complexTarget, const ConversionRates &ratesInfo, */
-/* UErrorCode &status) */
-/* : ConverterPreference(source, complexTarget, std::numeric_limits<double>::lowest(), ratesInfo, */
-/* status) {} */
-/* }; */
-
-/**
- * `UnitsRouter` responsible for converting from a single unit (such as `meter` or `meter-per-second`) to
- * one of the complex units based on the limits.
- * For example:
- * if the input is `meter` and the output as following
- * {`foot+inch`, limit: 3.0}
- * {`inch` , limit: no value (-inf)}
- * Thus means if the input in `meter` is greater than or equal to `3.0 feet`, the output will be in
- * `foot+inch`, otherwise, the output will be in `inch`.
- *
- * NOTE:
- * the output units and the their limits MUST BE in order, for example, if the output units, from the
- * previous example, are the following:
- * {`inch` , limit: no value (-inf)}
- * {`foot+inch`, limit: 3.0}
- * IN THIS CASE THE OUTPUT WILL BE ALWAYS IN `inch`.
- *
- * NOTE:
- * the output units and their limits will be extracted from the units preferences database by knowing
- * the followings:
- * - input unit
- * - locale
- * - usage
- *
- * DESIGN:
- * `UnitRouter` uses internally `ComplexUnitConverter` in order to convert the input units to the
- * desired complex units and to check the limit too.
- */
class U_I18N_API StubUnitsRouter {
public:
// As found in UnitsRouter
StubUnitsRouter(MeasureUnit inputUnit, StringPiece region, StringPiece usage,
UErrorCode &status);
- // WIP/FIXME: Possible improvement: with "Locale" instead of "StringPiece":
+ // TODO(units): consider this possible improvement for the constructor:
+ // passing "Locale" instead of "StringPiece region"? :
StubUnitsRouter(MeasureUnit inputUnit, Locale locale, StringPiece usage, UErrorCode &status);
- // WIP/FIXME: going via Measure is excessive when we specifically need a double.
+ // 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
+ // its own, represent mixed units. (i.e. do we want to have Measure support
+ // multi-valued mixed-units?)
MaybeStackVector<Measure> route(double quantity, UErrorCode &status) const;
MaybeStackVector<MeasureUnit> getOutputUnits() const;