summaryrefslogtreecommitdiffstats
path: root/intl/icu/source/i18n/number_longnames.h
blob: 56d8c9b24e8d713e79fe75385940140d0eff7f8c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
// © 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 &currency, 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 &micros, 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<LongNameHandler>::emplaceBack(): requires access to
    // the private constructors.
    friend class MemoryPool<LongNameHandler>;

    // 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 &micros,
                         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<UnicodeString> fMixedUnitData;

    // Formats the larger units of Mixed Unit measurements.
    LocalizedNumberFormatter fNumberFormatter;

    // Joins mixed units together.
    LocalPointer<ListFormatter> 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<LongNameHandler>::emplaceBack(): requires access to
    // the private constructors.
    friend class MemoryPool<MixedUnitLongNameHandler>;

    // 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 &micros,
                                         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<MeasureUnit> &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 &micros,
                         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<LongNameHandler> fLongNameHandlers;
    MemoryPool<MixedUnitLongNameHandler> fMixedUnitHandlers;
    // Unowned pointers to instances owned by MaybeStackVectors.
    MaybeStackArray<MicroPropsGenerator *, 8> fHandlers;
    // Each MeasureUnit corresponds to the same-index MicroPropsGenerator
    // pointed to in fHandlers.
    LocalArray<MeasureUnit> 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 */