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 &currency, 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 &micros, 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 
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 &micros,
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 
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 &micros,
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 &micros,
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 
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