// © 2017 and later: Unicode, Inc. and others. // License & terms of use: http://www.unicode.org/copyright.html #include "unicode/utypes.h" #if !UCONFIG_NO_FORMATTING #ifndef __NUMBER_LONGNAMES_H__ #define __NUMBER_LONGNAMES_H__ #include "cmemory.h" #include "unicode/listformatter.h" #include "unicode/uversion.h" #include "number_utils.h" #include "number_modifiers.h" U_NAMESPACE_BEGIN namespace number { namespace impl { // LongNameHandler takes care of formatting currency and measurement unit names, // as well as populating the gender of measure units. class LongNameHandler : public MicroPropsGenerator, public ModifierStore, public UMemory { public: static UnicodeString getUnitDisplayName( const Locale& loc, const MeasureUnit& unit, UNumberUnitWidth width, UErrorCode& status); // This function does not support inflections or other newer NumberFormatter // features: it exists to support the older not-recommended MeasureFormat. static UnicodeString getUnitPattern( const Locale& loc, const MeasureUnit& unit, UNumberUnitWidth width, StandardPlural::Form pluralForm, UErrorCode& status); static LongNameHandler* forCurrencyLongNames(const Locale &loc, const CurrencyUnit ¤cy, const PluralRules *rules, const MicroPropsGenerator *parent, UErrorCode &status); /** * Construct a localized LongNameHandler for the specified MeasureUnit. * * Mixed units are not supported, use MixedUnitLongNameHandler::forMeasureUnit. * * This function uses a fillIn instead of returning a pointer, because we * want to fill in instances in a MemoryPool (which cannot adopt pointers it * didn't create itself). * * @param loc The desired locale. * @param unitRef The measure unit to construct a LongNameHandler for. * @param width Specifies the desired unit rendering. * @param unitDisplayCase Specifies the desired grammatical case. If the * specified case is not found, we fall back to nominative or no-case. * @param rules Does not take ownership. * @param parent Does not take ownership. * @param fillIn Required. */ static void forMeasureUnit(const Locale &loc, const MeasureUnit &unitRef, const UNumberUnitWidth &width, const char *unitDisplayCase, const PluralRules *rules, const MicroPropsGenerator *parent, LongNameHandler *fillIn, UErrorCode &status); /** * Selects the plural-appropriate Modifier from the set of fModifiers based * on the plural form. */ void processQuantity(DecimalQuantity &quantity, MicroProps µs, UErrorCode &status) const override; const Modifier* getModifier(Signum signum, StandardPlural::Form plural) const override; private: // A set of pre-computed modifiers, one for each plural form. SimpleModifier fModifiers[StandardPlural::Form::COUNT]; // Not owned const PluralRules *rules; // Not owned const MicroPropsGenerator *parent; // Grammatical gender of the formatted result. Not owned: must point at // static or global strings. const char *gender = ""; LongNameHandler(const PluralRules *rules, const MicroPropsGenerator *parent) : rules(rules), parent(parent) { } LongNameHandler() : rules(nullptr), parent(nullptr) { } // Enables MemoryPool::emplaceBack(): requires access to // the private constructors. friend class MemoryPool; // Allow macrosToMicroGenerator to call the private default constructor. friend class NumberFormatterImpl; // Fills in LongNameHandler fields for formatting units identified `unit`. static void forArbitraryUnit(const Locale &loc, const MeasureUnit &unit, const UNumberUnitWidth &width, const char *unitDisplayCase, LongNameHandler *fillIn, UErrorCode &status); // Roughly corresponds to patternTimes(...) in the spec: // https://unicode.org/reports/tr35/tr35-general.html#compound-units // // productUnit is an rvalue reference to indicate this function consumes it, // leaving it in a not-useful / undefined state. static void processPatternTimes(MeasureUnitImpl &&productUnit, Locale loc, const UNumberUnitWidth &width, const char *caseVariant, UnicodeString *outArray, UErrorCode &status); // Sets fModifiers to use the patterns from `simpleFormats`. void simpleFormatsToModifiers(const UnicodeString *simpleFormats, Field field, UErrorCode &status); // Sets fModifiers to a combination of `leadFormats` (one per plural form) // and `trailFormat` appended to each. // // With a leadFormat of "{0}m" and a trailFormat of "{0}/s", it produces a // pattern of "{0}m/s" by inserting each leadFormat pattern into trailFormat. void multiSimpleFormatsToModifiers(const UnicodeString *leadFormats, UnicodeString trailFormat, Field field, UErrorCode &status); }; // Similar to LongNameHandler, but only for MIXED units. class MixedUnitLongNameHandler : public MicroPropsGenerator, public ModifierStore, public UMemory { public: /** * Construct a localized MixedUnitLongNameHandler for the specified * MeasureUnit. It must be a MIXED unit. * * This function uses a fillIn instead of returning a pointer, because we * want to fill in instances in a MemoryPool (which cannot adopt pointers it * didn't create itself). * * @param loc The desired locale. * @param mixedUnit The mixed measure unit to construct a * MixedUnitLongNameHandler for. * @param width Specifies the desired unit rendering. * @param unitDisplayCase Specifies the desired grammatical case. If the * specified case is not found, we fall back to nominative or no-case. * @param rules Does not take ownership. * @param parent Does not take ownership. * @param fillIn Required. */ static void forMeasureUnit(const Locale &loc, const MeasureUnit &mixedUnit, const UNumberUnitWidth &width, const char *unitDisplayCase, const PluralRules *rules, const MicroPropsGenerator *parent, MixedUnitLongNameHandler *fillIn, UErrorCode &status); /** * Produces a plural-appropriate Modifier for a mixed unit: `quantity` is * taken as the final smallest unit, while the larger unit values must be * provided via `micros.mixedMeasures`. */ void processQuantity(DecimalQuantity &quantity, MicroProps µs, UErrorCode &status) const override; // Required for ModifierStore. And ModifierStore is required by // SimpleModifier constructor's last parameter. We assert his will never get // called though. const Modifier *getModifier(Signum signum, StandardPlural::Form plural) const override; private: // Not owned const PluralRules *rules; // Not owned const MicroPropsGenerator *parent; // Total number of units in the MeasureUnit this handler was configured for: // for "foot-and-inch", this will be 2. int32_t fMixedUnitCount = 1; // Stores unit data for each of the individual units. For each unit, it // stores ARRAY_LENGTH strings, as returned by getMeasureData. (Each unit // with index `i` has ARRAY_LENGTH strings starting at index // `i*ARRAY_LENGTH` in this array.) LocalArray fMixedUnitData; // Formats the larger units of Mixed Unit measurements. LocalizedNumberFormatter fNumberFormatter; // Joins mixed units together. LocalPointer fListFormatter; MixedUnitLongNameHandler(const PluralRules *rules, const MicroPropsGenerator *parent) : rules(rules), parent(parent) { } MixedUnitLongNameHandler() : rules(nullptr), parent(nullptr) { } // Allow macrosToMicroGenerator to call the private default constructor. friend class NumberFormatterImpl; // Enables MemoryPool::emplaceBack(): requires access to // the private constructors. friend class MemoryPool; // For a mixed unit, returns a Modifier that takes only one parameter: the // smallest and final unit of the set. The bigger units' values and labels // get baked into this Modifier, together with the unit label of the final // unit. const Modifier *getMixedUnitModifier(DecimalQuantity &quantity, MicroProps µs, UErrorCode &status) const; }; /** * A MicroPropsGenerator that multiplexes between different LongNameHandlers, * depending on the outputUnit. * * See processQuantity() for the input requirements. */ class LongNameMultiplexer : public MicroPropsGenerator, public UMemory { public: // Produces a multiplexer for LongNameHandlers, one for each unit in // `units`. An individual unit might be a mixed unit. static LongNameMultiplexer *forMeasureUnits(const Locale &loc, const MaybeStackVector &units, const UNumberUnitWidth &width, const char *unitDisplayCase, const PluralRules *rules, const MicroPropsGenerator *parent, UErrorCode &status); // The output unit must be provided via `micros.outputUnit`, it must match // one of the units provided to the factory function. void processQuantity(DecimalQuantity &quantity, MicroProps µs, UErrorCode &status) const override; private: /** * 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. */ MemoryPool fLongNameHandlers; MemoryPool fMixedUnitHandlers; // Unowned pointers to instances owned by MaybeStackVectors. MaybeStackArray fHandlers; // Each MeasureUnit corresponds to the same-index MicroPropsGenerator // pointed to in fHandlers. LocalArray fMeasureUnits; const MicroPropsGenerator *fParent; LongNameMultiplexer(const MicroPropsGenerator *parent) : fParent(parent) { } }; } // namespace impl } // namespace number U_NAMESPACE_END #endif //__NUMBER_LONGNAMES_H__ #endif /* #if !UCONFIG_NO_FORMATTING */