summaryrefslogtreecommitdiff
path: root/deps/icu-small/source/i18n/number_types.h
blob: 225d1e577504900747b057169003c8f5e544f5ca (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
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
// © 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_TYPES_H__
#define __NUMBER_TYPES_H__

#include <cstdint>
#include "unicode/decimfmt.h"
#include "unicode/unum.h"
#include "unicode/numsys.h"
#include "unicode/numberformatter.h"
#include "unicode/utf16.h"
#include "uassert.h"
#include "unicode/platform.h"
#include "unicode/uniset.h"
#include "standardplural.h"

U_NAMESPACE_BEGIN namespace number {
namespace impl {

// Typedef several enums for brevity and for easier comparison to Java.

// Convention: bottom 4 bits for field, top 4 bits for field category.
// Field category 0 implies the number category so that the number field
// literals can be directly passed as a Field type.
// See the helper functions in "NumFieldUtils" in number_utils.h
typedef uint8_t Field;

typedef UNumberFormatRoundingMode RoundingMode;

typedef UNumberFormatPadPosition PadPosition;

typedef UNumberCompactStyle CompactStyle;

// ICU4J Equivalent: RoundingUtils.MAX_INT_FRAC_SIG
static constexpr int32_t kMaxIntFracSig = 999;

// ICU4J Equivalent: RoundingUtils.DEFAULT_ROUNDING_MODE
static constexpr RoundingMode kDefaultMode = RoundingMode::UNUM_FOUND_HALFEVEN;

// ICU4J Equivalent: Padder.FALLBACK_PADDING_STRING
static constexpr char16_t kFallbackPaddingString[] = u" ";

// Forward declarations:

class Modifier;
class MutablePatternModifier;
class DecimalQuantity;
class NumberStringBuilder;
class ModifierStore;
struct MicroProps;


enum AffixPatternType {
    // Represents a literal character; the value is stored in the code point field.
            TYPE_CODEPOINT = 0,

    // Represents a minus sign symbol '-'.
            TYPE_MINUS_SIGN = -1,

    // Represents a plus sign symbol '+'.
            TYPE_PLUS_SIGN = -2,

    // Represents a percent sign symbol '%'.
            TYPE_PERCENT = -3,

    // Represents a permille sign symbol '‰'.
            TYPE_PERMILLE = -4,

    // Represents a single currency symbol '¤'.
            TYPE_CURRENCY_SINGLE = -5,

    // Represents a double currency symbol '¤¤'.
            TYPE_CURRENCY_DOUBLE = -6,

    // Represents a triple currency symbol '¤¤¤'.
            TYPE_CURRENCY_TRIPLE = -7,

    // Represents a quadruple currency symbol '¤¤¤¤'.
            TYPE_CURRENCY_QUAD = -8,

    // Represents a quintuple currency symbol '¤¤¤¤¤'.
            TYPE_CURRENCY_QUINT = -9,

    // Represents a sequence of six or more currency symbols.
            TYPE_CURRENCY_OVERFLOW = -15
};

enum CompactType {
    TYPE_DECIMAL, TYPE_CURRENCY
};


class U_I18N_API AffixPatternProvider {
  public:
    static const int32_t AFFIX_PLURAL_MASK = 0xff;
    static const int32_t AFFIX_PREFIX = 0x100;
    static const int32_t AFFIX_NEGATIVE_SUBPATTERN = 0x200;
    static const int32_t AFFIX_PADDING = 0x400;

    // Convenience compound flags
    static const int32_t AFFIX_POS_PREFIX = AFFIX_PREFIX;
    static const int32_t AFFIX_POS_SUFFIX = 0;
    static const int32_t AFFIX_NEG_PREFIX = AFFIX_PREFIX | AFFIX_NEGATIVE_SUBPATTERN;
    static const int32_t AFFIX_NEG_SUFFIX = AFFIX_NEGATIVE_SUBPATTERN;

    virtual ~AffixPatternProvider();

    virtual char16_t charAt(int flags, int i) const = 0;

    virtual int length(int flags) const = 0;

    virtual UnicodeString getString(int flags) const = 0;

    virtual bool hasCurrencySign() const = 0;

    virtual bool positiveHasPlusSign() const = 0;

    virtual bool hasNegativeSubpattern() const = 0;

    virtual bool negativeHasMinusSign() const = 0;

    virtual bool containsSymbolType(AffixPatternType, UErrorCode&) const = 0;

    /**
     * True if the pattern has a number placeholder like "0" or "#,##0.00"; false if the pattern does not
     * have one. This is used in cases like compact notation, where the pattern replaces the entire
     * number instead of rendering the number.
     */
    virtual bool hasBody() const = 0;
};


/**
 * A Modifier is an object that can be passed through the formatting pipeline until it is finally applied to the string
 * builder. A Modifier usually contains a prefix and a suffix that are applied, but it could contain something else,
 * like a {@link com.ibm.icu.text.SimpleFormatter} pattern.
 *
 * A Modifier is usually immutable, except in cases such as {@link MutablePatternModifier}, which are mutable for performance
 * reasons.
 *
 * Exported as U_I18N_API because it is a base class for other exported types
 */
class U_I18N_API Modifier {
  public:
    virtual ~Modifier();

    /**
     * Apply this Modifier to the string builder.
     *
     * @param output
     *            The string builder to which to apply this modifier.
     * @param leftIndex
     *            The left index of the string within the builder. Equal to 0 when only one number is being formatted.
     * @param rightIndex
     *            The right index of the string within the string builder. Equal to length when only one number is being
     *            formatted.
     * @return The number of characters (UTF-16 code units) that were added to the string builder.
     */
    virtual int32_t apply(NumberStringBuilder& output, int leftIndex, int rightIndex,
                          UErrorCode& status) const = 0;

    /**
     * Gets the length of the prefix. This information can be used in combination with {@link #apply} to extract the
     * prefix and suffix strings.
     *
     * @return The number of characters (UTF-16 code units) in the prefix.
     */
    virtual int32_t getPrefixLength() const = 0;

    /**
     * Returns the number of code points in the modifier, prefix plus suffix.
     */
    virtual int32_t getCodePointCount() const = 0;

    /**
     * Whether this modifier is strong. If a modifier is strong, it should always be applied immediately and not allowed
     * to bubble up. With regard to padding, strong modifiers are considered to be on the inside of the prefix and
     * suffix.
     *
     * @return Whether the modifier is strong.
     */
    virtual bool isStrong() const = 0;

    /**
     * Whether the modifier contains at least one occurrence of the given field.
     */
    virtual bool containsField(UNumberFormatFields field) const = 0;

    /**
     * A fill-in for getParameters(). obj will always be set; if non-null, the other
     * two fields are also safe to read.
     */
    struct U_I18N_API Parameters {
        const ModifierStore* obj = nullptr;
        int8_t signum;
        StandardPlural::Form plural;

        Parameters();
        Parameters(const ModifierStore* _obj, int8_t _signum, StandardPlural::Form _plural);
    };

    /**
     * Gets a set of "parameters" for this Modifier.
     *
     * TODO: Make this return a `const Parameters*` more like Java?
     */
    virtual void getParameters(Parameters& output) const = 0;

    /**
     * Returns whether this Modifier is *semantically equivalent* to the other Modifier;
     * in many cases, this is the same as equal, but parameters should be ignored.
     */
    virtual bool semanticallyEquivalent(const Modifier& other) const = 0;
};


/**
 * This is *not* a modifier; rather, it is an object that can return modifiers
 * based on given parameters.
 *
 * Exported as U_I18N_API because it is a base class for other exported types.
 */
class U_I18N_API ModifierStore {
  public:
    virtual ~ModifierStore();

    /**
     * Returns a Modifier with the given parameters (best-effort).
     */
    virtual const Modifier* getModifier(int8_t signum, StandardPlural::Form plural) const = 0;
};


/**
 * This interface is used when all number formatting settings, including the locale, are known, except for the quantity
 * itself. The {@link #processQuantity} method performs the final step in the number processing pipeline: it uses the
 * quantity to generate a finalized {@link MicroProps}, which can be used to render the number to output.
 *
 * <p>
 * In other words, this interface is used for the parts of number processing that are <em>quantity-dependent</em>.
 *
 * <p>
 * In order to allow for multiple different objects to all mutate the same MicroProps, a "chain" of MicroPropsGenerators
 * are linked together, and each one is responsible for manipulating a certain quantity-dependent part of the
 * MicroProps. At the tail of the linked list is a base instance of {@link MicroProps} with properties that are not
 * quantity-dependent. Each element in the linked list calls {@link #processQuantity} on its "parent", then does its
 * work, and then returns the result.
 *
 * Exported as U_I18N_API because it is a base class for other exported types
 *
 */
class U_I18N_API MicroPropsGenerator {
  public:
    virtual ~MicroPropsGenerator();

    /**
     * Considers the given {@link DecimalQuantity}, optionally mutates it, and returns a {@link MicroProps}.
     *
     * @param quantity
     *            The quantity for consideration and optional mutation.
     * @param micros
     *            The MicroProps instance to populate.
     * @return A MicroProps instance resolved for the quantity.
     */
    virtual void processQuantity(DecimalQuantity& quantity, MicroProps& micros,
                                 UErrorCode& status) const = 0;
};

/**
 * An interface used by compact notation and scientific notation to choose a multiplier while rounding.
 */
class MultiplierProducer {
  public:
    virtual ~MultiplierProducer();

    /**
     * Maps a magnitude to a multiplier in powers of ten. For example, in compact notation in English, a magnitude of 5
     * (e.g., 100,000) should return a multiplier of -3, since the number is displayed in thousands.
     *
     * @param magnitude
     *            The power of ten of the input number.
     * @return The shift in powers of ten.
     */
    virtual int32_t getMultiplier(int32_t magnitude) const = 0;
};

// Exported as U_I18N_API because it is a public member field of exported DecimalFormatProperties
template<typename T>
class U_I18N_API NullableValue {
  public:
    NullableValue()
            : fNull(true) {}

    NullableValue(const NullableValue<T>& other) = default;

    explicit NullableValue(const T& other) {
        fValue = other;
        fNull = false;
    }

    NullableValue<T>& operator=(const NullableValue<T>& other) {
        fNull = other.fNull;
        if (!fNull) {
            fValue = other.fValue;
        }
        return *this;
    }

    NullableValue<T>& operator=(const T& other) {
        fValue = other;
        fNull = false;
        return *this;
    }

    bool operator==(const NullableValue& other) const {
        // "fValue == other.fValue" returns UBool, not bool (causes compiler warnings)
        return fNull ? other.fNull : (other.fNull ? false : static_cast<bool>(fValue == other.fValue));
    }

    void nullify() {
        // TODO: It might be nice to call the destructor here.
        fNull = true;
    }

    bool isNull() const {
        return fNull;
    }

    T get(UErrorCode& status) const {
        if (fNull) {
            status = U_UNDEFINED_VARIABLE;
        }
        return fValue;
    }

    T getNoError() const {
        return fValue;
    }

    T getOrDefault(T defaultValue) const {
        return fNull ? defaultValue : fValue;
    }

  private:
    bool fNull;
    T fValue;
};


} // namespace impl
} // namespace number
U_NAMESPACE_END

#endif //__NUMBER_TYPES_H__

#endif /* #if !UCONFIG_NO_FORMATTING */