Coverage Report

Created: 2025-01-28 06:38

/src/icu/source/i18n/number_modifiers.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_MODIFIERS_H__
8
#define __NUMBER_MODIFIERS_H__
9
10
#include <algorithm>
11
#include <cstdint>
12
#include "unicode/uniset.h"
13
#include "unicode/simpleformatter.h"
14
#include "standardplural.h"
15
#include "formatted_string_builder.h"
16
#include "number_types.h"
17
18
U_NAMESPACE_BEGIN namespace number {
19
namespace impl {
20
21
/**
22
 * The canonical implementation of {@link Modifier}, containing a prefix and suffix string.
23
 * TODO: This is not currently being used by real code and could be removed.
24
 */
25
class U_I18N_API ConstantAffixModifier : public Modifier, public UObject {
26
  public:
27
    ConstantAffixModifier(const UnicodeString &prefix, const UnicodeString &suffix, Field field,
28
                          bool strong)
29
0
            : fPrefix(prefix), fSuffix(suffix), fField(field), fStrong(strong) {}
30
31
    int32_t apply(FormattedStringBuilder &output, int32_t leftIndex, int32_t rightIndex,
32
                  UErrorCode &status) const U_OVERRIDE;
33
34
    int32_t getPrefixLength() const U_OVERRIDE;
35
36
    int32_t getCodePointCount() const U_OVERRIDE;
37
38
    bool isStrong() const U_OVERRIDE;
39
40
    bool containsField(Field field) const U_OVERRIDE;
41
42
    void getParameters(Parameters& output) const U_OVERRIDE;
43
44
    bool semanticallyEquivalent(const Modifier& other) const U_OVERRIDE;
45
46
  private:
47
    UnicodeString fPrefix;
48
    UnicodeString fSuffix;
49
    Field fField;
50
    bool fStrong;
51
};
52
53
/**
54
 * The second primary implementation of {@link Modifier}, this one consuming a {@link SimpleFormatter}
55
 * pattern.
56
 */
57
class U_I18N_API SimpleModifier : public Modifier, public UMemory {
58
  public:
59
    SimpleModifier(const SimpleFormatter &simpleFormatter, Field field, bool strong);
60
61
    SimpleModifier(const SimpleFormatter &simpleFormatter, Field field, bool strong,
62
                   const Modifier::Parameters parameters);
63
64
    // Default constructor for LongNameHandler.h
65
    SimpleModifier();
66
67
    int32_t apply(FormattedStringBuilder &output, int32_t leftIndex, int32_t rightIndex,
68
                  UErrorCode &status) const U_OVERRIDE;
69
70
    int32_t getPrefixLength() const U_OVERRIDE;
71
72
    int32_t getCodePointCount() const U_OVERRIDE;
73
74
    bool isStrong() const U_OVERRIDE;
75
76
    bool containsField(Field field) const U_OVERRIDE;
77
78
    void getParameters(Parameters& output) const U_OVERRIDE;
79
80
    bool semanticallyEquivalent(const Modifier& other) const U_OVERRIDE;
81
82
    /**
83
     * TODO: This belongs in SimpleFormatterImpl. The only reason I haven't moved it there yet is because
84
     * FormattedStringBuilder is an internal class and SimpleFormatterImpl feels like it should not depend on it.
85
     *
86
     * <p>
87
     * Formats a value that is already stored inside the StringBuilder <code>result</code> between the indices
88
     * <code>startIndex</code> and <code>endIndex</code> by inserting characters before the start index and after the
89
     * end index.
90
     *
91
     * <p>
92
     * This is well-defined only for patterns with exactly one argument.
93
     *
94
     * @param result
95
     *            The StringBuilder containing the value argument.
96
     * @param startIndex
97
     *            The left index of the value within the string builder.
98
     * @param endIndex
99
     *            The right index of the value within the string builder.
100
     * @return The number of characters (UTF-16 code points) that were added to the StringBuilder.
101
     */
102
    int32_t
103
    formatAsPrefixSuffix(FormattedStringBuilder& result, int32_t startIndex, int32_t endIndex,
104
                         UErrorCode& status) const;
105
106
    /**
107
     * TODO: Like above, this belongs with the rest of the SimpleFormatterImpl code.
108
     * I put it here so that the SimpleFormatter uses in FormattedStringBuilder are near each other.
109
     *
110
     * <p>
111
     * Applies the compiled two-argument pattern to the FormattedStringBuilder.
112
     *
113
     * <p>
114
     * This method is optimized for the case where the prefix and suffix are often empty, such as
115
     * in the range pattern like "{0}-{1}".
116
     */
117
    static int32_t
118
    formatTwoArgPattern(const SimpleFormatter& compiled, FormattedStringBuilder& result,
119
                        int32_t index, int32_t* outPrefixLength, int32_t* outSuffixLength,
120
                        Field field, UErrorCode& status);
121
122
  private:
123
    UnicodeString fCompiledPattern;
124
    Field fField;
125
    bool fStrong = false;
126
    int32_t fPrefixLength = 0;
127
    int32_t fSuffixOffset = -1;
128
    int32_t fSuffixLength = 0;
129
    Modifier::Parameters fParameters;
130
};
131
132
/**
133
 * An implementation of {@link Modifier} that allows for multiple types of fields in the same modifier. Constructed
134
 * based on the contents of two {@link FormattedStringBuilder} instances (one for the prefix, one for the suffix).
135
 */
136
class U_I18N_API ConstantMultiFieldModifier : public Modifier, public UMemory {
137
  public:
138
    ConstantMultiFieldModifier(
139
            const FormattedStringBuilder &prefix,
140
            const FormattedStringBuilder &suffix,
141
            bool overwrite,
142
            bool strong,
143
            const Modifier::Parameters parameters)
144
      : fPrefix(prefix),
145
        fSuffix(suffix),
146
        fOverwrite(overwrite),
147
        fStrong(strong),
148
0
        fParameters(parameters) {}
149
150
    ConstantMultiFieldModifier(
151
            const FormattedStringBuilder &prefix,
152
            const FormattedStringBuilder &suffix,
153
            bool overwrite,
154
            bool strong)
155
0
      : fPrefix(prefix),
156
0
        fSuffix(suffix),
157
0
        fOverwrite(overwrite),
158
0
        fStrong(strong) {}
159
160
    int32_t apply(FormattedStringBuilder &output, int32_t leftIndex, int32_t rightIndex,
161
                  UErrorCode &status) const U_OVERRIDE;
162
163
    int32_t getPrefixLength() const U_OVERRIDE;
164
165
    int32_t getCodePointCount() const U_OVERRIDE;
166
167
    bool isStrong() const U_OVERRIDE;
168
169
    bool containsField(Field field) const U_OVERRIDE;
170
171
    void getParameters(Parameters& output) const U_OVERRIDE;
172
173
    bool semanticallyEquivalent(const Modifier& other) const U_OVERRIDE;
174
175
  protected:
176
    // NOTE: In Java, these are stored as array pointers. In C++, the FormattedStringBuilder is stored by
177
    // value and is treated internally as immutable.
178
    FormattedStringBuilder fPrefix;
179
    FormattedStringBuilder fSuffix;
180
    bool fOverwrite;
181
    bool fStrong;
182
    Modifier::Parameters fParameters;
183
};
184
185
/** Identical to {@link ConstantMultiFieldModifier}, but supports currency spacing. */
186
class U_I18N_API CurrencySpacingEnabledModifier : public ConstantMultiFieldModifier {
187
  public:
188
    /** Safe code path */
189
    CurrencySpacingEnabledModifier(
190
            const FormattedStringBuilder &prefix,
191
            const FormattedStringBuilder &suffix,
192
            bool overwrite,
193
            bool strong,
194
            const DecimalFormatSymbols &symbols,
195
            UErrorCode &status);
196
197
    int32_t apply(FormattedStringBuilder &output, int32_t leftIndex, int32_t rightIndex,
198
                  UErrorCode &status) const U_OVERRIDE;
199
200
    /** Unsafe code path */
201
    static int32_t
202
    applyCurrencySpacing(FormattedStringBuilder &output, int32_t prefixStart, int32_t prefixLen,
203
                         int32_t suffixStart, int32_t suffixLen, const DecimalFormatSymbols &symbols,
204
                         UErrorCode &status);
205
206
  private:
207
    UnicodeSet fAfterPrefixUnicodeSet;
208
    UnicodeString fAfterPrefixInsert;
209
    UnicodeSet fBeforeSuffixUnicodeSet;
210
    UnicodeString fBeforeSuffixInsert;
211
212
    enum EAffix {
213
        PREFIX, SUFFIX
214
    };
215
216
    enum EPosition {
217
        IN_CURRENCY, IN_NUMBER
218
    };
219
220
    /** Unsafe code path */
221
    static int32_t applyCurrencySpacingAffix(FormattedStringBuilder &output, int32_t index, EAffix affix,
222
                                             const DecimalFormatSymbols &symbols, UErrorCode &status);
223
224
    static UnicodeSet
225
    getUnicodeSet(const DecimalFormatSymbols &symbols, EPosition position, EAffix affix,
226
                  UErrorCode &status);
227
228
    static UnicodeString
229
    getInsertString(const DecimalFormatSymbols &symbols, EAffix affix, UErrorCode &status);
230
};
231
232
/** A Modifier that does not do anything. */
233
class U_I18N_API EmptyModifier : public Modifier, public UMemory {
234
  public:
235
0
    explicit EmptyModifier(bool isStrong) : fStrong(isStrong) {}
236
237
    int32_t apply(FormattedStringBuilder &output, int32_t leftIndex, int32_t rightIndex,
238
0
                  UErrorCode &status) const U_OVERRIDE {
239
0
        (void)output;
240
0
        (void)leftIndex;
241
0
        (void)rightIndex;
242
0
        (void)status;
243
0
        return 0;
244
0
    }
245
246
0
    int32_t getPrefixLength() const U_OVERRIDE {
247
0
        return 0;
248
0
    }
249
250
0
    int32_t getCodePointCount() const U_OVERRIDE {
251
0
        return 0;
252
0
    }
253
254
0
    bool isStrong() const U_OVERRIDE {
255
0
        return fStrong;
256
0
    }
257
258
0
    bool containsField(Field field) const U_OVERRIDE {
259
0
        (void)field;
260
0
        return false;
261
0
    }
262
263
0
    void getParameters(Parameters& output) const U_OVERRIDE {
264
0
        output.obj = nullptr;
265
0
    }
266
267
0
    bool semanticallyEquivalent(const Modifier& other) const U_OVERRIDE {
268
0
        return other.getCodePointCount() == 0;
269
0
    }
270
271
  private:
272
    bool fStrong;
273
};
274
275
/**
276
 * This implementation of ModifierStore adopts Modifier pointers.
277
 */
278
class U_I18N_API AdoptingModifierStore : public ModifierStore, public UMemory {
279
  public:
280
    virtual ~AdoptingModifierStore();
281
282
    static constexpr StandardPlural::Form DEFAULT_STANDARD_PLURAL = StandardPlural::OTHER;
283
284
0
    AdoptingModifierStore() = default;
285
286
    // No copying!
287
    AdoptingModifierStore(const AdoptingModifierStore &other) = delete;
288
289
    /**
290
     * Sets the Modifier with the specified signum and plural form.
291
     */
292
0
    void adoptModifier(Signum signum, StandardPlural::Form plural, const Modifier *mod) {
293
0
        U_ASSERT(mods[getModIndex(signum, plural)] == nullptr);
294
0
        mods[getModIndex(signum, plural)] = mod;
295
0
    }
296
297
    /**
298
     * Sets the Modifier with the specified signum.
299
     * The modifier will apply to all plural forms.
300
     */
301
0
    void adoptModifierWithoutPlural(Signum signum, const Modifier *mod) {
302
0
        U_ASSERT(mods[getModIndex(signum, DEFAULT_STANDARD_PLURAL)] == nullptr);
303
0
        mods[getModIndex(signum, DEFAULT_STANDARD_PLURAL)] = mod;
304
0
    }
305
306
    /** Returns a reference to the modifier; no ownership change. */
307
0
    const Modifier *getModifier(Signum signum, StandardPlural::Form plural) const U_OVERRIDE {
308
0
        const Modifier* modifier = mods[getModIndex(signum, plural)];
309
0
        if (modifier == nullptr && plural != DEFAULT_STANDARD_PLURAL) {
310
0
            modifier = mods[getModIndex(signum, DEFAULT_STANDARD_PLURAL)];
311
0
        }
312
0
        return modifier;
313
0
    }
314
315
    /** Returns a reference to the modifier; no ownership change. */
316
0
    const Modifier *getModifierWithoutPlural(Signum signum) const {
317
0
        return mods[getModIndex(signum, DEFAULT_STANDARD_PLURAL)];
318
0
    }
319
320
  private:
321
    // NOTE: mods is zero-initialized (to nullptr)
322
    const Modifier *mods[4 * StandardPlural::COUNT] = {};
323
324
0
    inline static int32_t getModIndex(Signum signum, StandardPlural::Form plural) {
325
0
        U_ASSERT(signum >= 0 && signum < SIGNUM_COUNT);
326
0
        U_ASSERT(plural >= 0 && plural < StandardPlural::COUNT);
327
0
        return static_cast<int32_t>(plural) * SIGNUM_COUNT + signum;
328
0
    }
329
};
330
331
} // namespace impl
332
} // namespace number
333
U_NAMESPACE_END
334
335
336
#endif //__NUMBER_MODIFIERS_H__
337
338
#endif /* #if !UCONFIG_NO_FORMATTING */