1 // © 2017 and later: Unicode, Inc. and others. 2 // License & terms of use: http://www.unicode.org/copyright.html 3 4 #include "unicode/utypes.h" 5 6 #if !UCONFIG_NO_FORMATTING 7 #ifndef __NUMBER_LONGNAMES_H__ 8 #define __NUMBER_LONGNAMES_H__ 9 10 #include "cmemory.h" 11 #include "unicode/listformatter.h" 12 #include "unicode/uversion.h" 13 #include "number_utils.h" 14 #include "number_modifiers.h" 15 16 U_NAMESPACE_BEGIN namespace number { 17 namespace impl { 18 19 // LongNameHandler takes care of formatting currency and measurement unit names, 20 // as well as populating the gender of measure units. 21 class LongNameHandler : public MicroPropsGenerator, public ModifierStore, public UMemory { 22 public: 23 static UnicodeString getUnitDisplayName( 24 const Locale& loc, 25 const MeasureUnit& unit, 26 UNumberUnitWidth width, 27 UErrorCode& status); 28 29 // This function does not support inflections or other newer NumberFormatter 30 // features: it exists to support the older not-recommended MeasureFormat. 31 static UnicodeString getUnitPattern( 32 const Locale& loc, 33 const MeasureUnit& unit, 34 UNumberUnitWidth width, 35 StandardPlural::Form pluralForm, 36 UErrorCode& status); 37 38 static LongNameHandler* 39 forCurrencyLongNames(const Locale &loc, const CurrencyUnit ¤cy, const PluralRules *rules, 40 const MicroPropsGenerator *parent, UErrorCode &status); 41 42 /** 43 * Construct a localized LongNameHandler for the specified MeasureUnit. 44 * 45 * Mixed units are not supported, use MixedUnitLongNameHandler::forMeasureUnit. 46 * 47 * This function uses a fillIn instead of returning a pointer, because we 48 * want to fill in instances in a MemoryPool (which cannot adopt pointers it 49 * didn't create itself). 50 * 51 * @param loc The desired locale. 52 * @param unitRef The measure unit to construct a LongNameHandler for. 53 * @param width Specifies the desired unit rendering. 54 * @param unitDisplayCase Specifies the desired grammatical case. If the 55 * specified case is not found, we fall back to nominative or no-case. 56 * @param rules Does not take ownership. 57 * @param parent Does not take ownership. 58 * @param fillIn Required. 59 */ 60 static void forMeasureUnit(const Locale &loc, 61 const MeasureUnit &unitRef, 62 const UNumberUnitWidth &width, 63 const char *unitDisplayCase, 64 const PluralRules *rules, 65 const MicroPropsGenerator *parent, 66 LongNameHandler *fillIn, 67 UErrorCode &status); 68 69 /** 70 * Selects the plural-appropriate Modifier from the set of fModifiers based 71 * on the plural form. 72 */ 73 void 74 processQuantity(DecimalQuantity &quantity, MicroProps µs, UErrorCode &status) const override; 75 76 const Modifier* getModifier(Signum signum, StandardPlural::Form plural) const override; 77 78 private: 79 // A set of pre-computed modifiers, one for each plural form. 80 SimpleModifier fModifiers[StandardPlural::Form::COUNT]; 81 // Not owned 82 const PluralRules *rules; 83 // Not owned 84 const MicroPropsGenerator *parent; 85 // Grammatical gender of the formatted result. Not owned: must point at 86 // static or global strings. 87 const char *gender = ""; 88 LongNameHandler(const PluralRules * rules,const MicroPropsGenerator * parent)89 LongNameHandler(const PluralRules *rules, const MicroPropsGenerator *parent) 90 : rules(rules), parent(parent) { 91 } 92 LongNameHandler()93 LongNameHandler() : rules(nullptr), parent(nullptr) { 94 } 95 96 // Enables MemoryPool<LongNameHandler>::emplaceBack(): requires access to 97 // the private constructors. 98 friend class MemoryPool<LongNameHandler>; 99 100 // Allow macrosToMicroGenerator to call the private default constructor. 101 friend class NumberFormatterImpl; 102 103 // Fills in LongNameHandler fields for formatting units identified `unit`. 104 static void forArbitraryUnit(const Locale &loc, 105 const MeasureUnit &unit, 106 const UNumberUnitWidth &width, 107 const char *unitDisplayCase, 108 LongNameHandler *fillIn, 109 UErrorCode &status); 110 111 // Roughly corresponds to patternTimes(...) in the spec: 112 // https://unicode.org/reports/tr35/tr35-general.html#compound-units 113 // 114 // productUnit is an rvalue reference to indicate this function consumes it, 115 // leaving it in a not-useful / undefined state. 116 static void processPatternTimes(MeasureUnitImpl &&productUnit, 117 Locale loc, 118 const UNumberUnitWidth &width, 119 const char *caseVariant, 120 UnicodeString *outArray, 121 UErrorCode &status); 122 123 // Sets fModifiers to use the patterns from `simpleFormats`. 124 void simpleFormatsToModifiers(const UnicodeString *simpleFormats, Field field, UErrorCode &status); 125 126 // Sets fModifiers to a combination of `leadFormats` (one per plural form) 127 // and `trailFormat` appended to each. 128 // 129 // With a leadFormat of "{0}m" and a trailFormat of "{0}/s", it produces a 130 // pattern of "{0}m/s" by inserting each leadFormat pattern into trailFormat. 131 void multiSimpleFormatsToModifiers(const UnicodeString *leadFormats, UnicodeString trailFormat, 132 Field field, UErrorCode &status); 133 }; 134 135 // Similar to LongNameHandler, but only for MIXED units. 136 class MixedUnitLongNameHandler : public MicroPropsGenerator, public ModifierStore, public UMemory { 137 public: 138 /** 139 * Construct a localized MixedUnitLongNameHandler for the specified 140 * MeasureUnit. It must be a MIXED unit. 141 * 142 * This function uses a fillIn instead of returning a pointer, because we 143 * want to fill in instances in a MemoryPool (which cannot adopt pointers it 144 * didn't create itself). 145 * 146 * @param loc The desired locale. 147 * @param mixedUnit The mixed measure unit to construct a 148 * MixedUnitLongNameHandler for. 149 * @param width Specifies the desired unit rendering. 150 * @param unitDisplayCase Specifies the desired grammatical case. If the 151 * specified case is not found, we fall back to nominative or no-case. 152 * @param rules Does not take ownership. 153 * @param parent Does not take ownership. 154 * @param fillIn Required. 155 */ 156 static void forMeasureUnit(const Locale &loc, 157 const MeasureUnit &mixedUnit, 158 const UNumberUnitWidth &width, 159 const char *unitDisplayCase, 160 const PluralRules *rules, 161 const MicroPropsGenerator *parent, 162 MixedUnitLongNameHandler *fillIn, 163 UErrorCode &status); 164 165 /** 166 * Produces a plural-appropriate Modifier for a mixed unit: `quantity` is 167 * taken as the final smallest unit, while the larger unit values must be 168 * provided via `micros.mixedMeasures`. 169 */ 170 void processQuantity(DecimalQuantity &quantity, MicroProps µs, 171 UErrorCode &status) const override; 172 173 // Required for ModifierStore. And ModifierStore is required by 174 // SimpleModifier constructor's last parameter. We assert his will never get 175 // called though. 176 const Modifier *getModifier(Signum signum, StandardPlural::Form plural) const override; 177 178 private: 179 // Not owned 180 const PluralRules *rules; 181 182 // Not owned 183 const MicroPropsGenerator *parent; 184 185 // Total number of units in the MeasureUnit this handler was configured for: 186 // for "foot-and-inch", this will be 2. 187 int32_t fMixedUnitCount = 1; 188 189 // Stores unit data for each of the individual units. For each unit, it 190 // stores ARRAY_LENGTH strings, as returned by getMeasureData. (Each unit 191 // with index `i` has ARRAY_LENGTH strings starting at index 192 // `i*ARRAY_LENGTH` in this array.) 193 LocalArray<UnicodeString> fMixedUnitData; 194 195 // Formats the larger units of Mixed Unit measurements. 196 LocalizedNumberFormatter fNumberFormatter; 197 198 // Joins mixed units together. 199 LocalPointer<ListFormatter> fListFormatter; 200 MixedUnitLongNameHandler(const PluralRules * rules,const MicroPropsGenerator * parent)201 MixedUnitLongNameHandler(const PluralRules *rules, const MicroPropsGenerator *parent) 202 : rules(rules), parent(parent) { 203 } 204 MixedUnitLongNameHandler()205 MixedUnitLongNameHandler() : rules(nullptr), parent(nullptr) { 206 } 207 208 // Allow macrosToMicroGenerator to call the private default constructor. 209 friend class NumberFormatterImpl; 210 211 // Enables MemoryPool<LongNameHandler>::emplaceBack(): requires access to 212 // the private constructors. 213 friend class MemoryPool<MixedUnitLongNameHandler>; 214 215 // For a mixed unit, returns a Modifier that takes only one parameter: the 216 // smallest and final unit of the set. The bigger units' values and labels 217 // get baked into this Modifier, together with the unit label of the final 218 // unit. 219 const Modifier *getMixedUnitModifier(DecimalQuantity &quantity, MicroProps µs, 220 UErrorCode &status) const; 221 }; 222 223 /** 224 * A MicroPropsGenerator that multiplexes between different LongNameHandlers, 225 * depending on the outputUnit. 226 * 227 * See processQuantity() for the input requirements. 228 */ 229 class LongNameMultiplexer : public MicroPropsGenerator, public UMemory { 230 public: 231 // Produces a multiplexer for LongNameHandlers, one for each unit in 232 // `units`. An individual unit might be a mixed unit. 233 static LongNameMultiplexer *forMeasureUnits(const Locale &loc, 234 const MaybeStackVector<MeasureUnit> &units, 235 const UNumberUnitWidth &width, 236 const char *unitDisplayCase, 237 const PluralRules *rules, 238 const MicroPropsGenerator *parent, 239 UErrorCode &status); 240 241 // The output unit must be provided via `micros.outputUnit`, it must match 242 // one of the units provided to the factory function. 243 void processQuantity(DecimalQuantity &quantity, MicroProps µs, 244 UErrorCode &status) const override; 245 246 private: 247 /** 248 * Because we only know which LongNameHandler we wish to call after calling 249 * earlier MicroPropsGenerators in the chain, LongNameMultiplexer keeps the 250 * parent link, while the LongNameHandlers are given no parents. 251 */ 252 MemoryPool<LongNameHandler> fLongNameHandlers; 253 MemoryPool<MixedUnitLongNameHandler> fMixedUnitHandlers; 254 // Unowned pointers to instances owned by MaybeStackVectors. 255 MaybeStackArray<MicroPropsGenerator *, 8> fHandlers; 256 // Each MeasureUnit corresponds to the same-index MicroPropsGenerator 257 // pointed to in fHandlers. 258 LocalArray<MeasureUnit> fMeasureUnits; 259 260 const MicroPropsGenerator *fParent; 261 LongNameMultiplexer(const MicroPropsGenerator * parent)262 LongNameMultiplexer(const MicroPropsGenerator *parent) : fParent(parent) { 263 } 264 }; 265 266 } // namespace impl 267 } // namespace number 268 U_NAMESPACE_END 269 270 #endif //__NUMBER_LONGNAMES_H__ 271 272 #endif /* #if !UCONFIG_NO_FORMATTING */ 273