Coverage Report

Created: 2023-02-22 06:51

/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 &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
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 &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
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 &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
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 */