/src/icu/source/i18n/number_longnames.h
Line | Count | Source (jump to first uncovered line) |
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 U_OVERRIDE; |
75 | | |
76 | | const Modifier* getModifier(Signum signum, StandardPlural::Form plural) const U_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 | | |
89 | | LongNameHandler(const PluralRules *rules, const MicroPropsGenerator *parent) |
90 | 0 | : rules(rules), parent(parent) { |
91 | 0 | } |
92 | | |
93 | 0 | LongNameHandler() : rules(nullptr), parent(nullptr) { |
94 | 0 | } |
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 U_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 U_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 | | |
201 | | MixedUnitLongNameHandler(const PluralRules *rules, const MicroPropsGenerator *parent) |
202 | 0 | : rules(rules), parent(parent) { |
203 | 0 | } |
204 | | |
205 | 0 | MixedUnitLongNameHandler() : rules(nullptr), parent(nullptr) { |
206 | 0 | } |
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 U_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 | | |
262 | 0 | LongNameMultiplexer(const MicroPropsGenerator *parent) : fParent(parent) { |
263 | 0 | } |
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 */ |