]>
Commit | Line | Data |
---|---|---|
0f5d89e8 A |
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_TYPES_H__ | |
8 | #define __NUMBER_TYPES_H__ | |
9 | ||
10 | #include <cstdint> | |
11 | #include "unicode/decimfmt.h" | |
12 | #include "unicode/unum.h" | |
13 | #include "unicode/numsys.h" | |
14 | #include "unicode/numberformatter.h" | |
15 | #include "unicode/utf16.h" | |
16 | #include "uassert.h" | |
17 | #include "unicode/platform.h" | |
18 | #include "unicode/uniset.h" | |
3d1f044b | 19 | #include "standardplural.h" |
0f5d89e8 A |
20 | |
21 | U_NAMESPACE_BEGIN namespace number { | |
22 | namespace impl { | |
23 | ||
24 | // Typedef several enums for brevity and for easier comparison to Java. | |
25 | ||
3d1f044b A |
26 | // Convention: bottom 4 bits for field, top 4 bits for field category. |
27 | // Field category 0 implies the number category so that the number field | |
28 | // literals can be directly passed as a Field type. | |
29 | // See the helper functions in "NumFieldUtils" in number_utils.h | |
30 | typedef uint8_t Field; | |
0f5d89e8 A |
31 | |
32 | typedef UNumberFormatRoundingMode RoundingMode; | |
33 | ||
34 | typedef UNumberFormatPadPosition PadPosition; | |
35 | ||
36 | typedef UNumberCompactStyle CompactStyle; | |
37 | ||
38 | // ICU4J Equivalent: RoundingUtils.MAX_INT_FRAC_SIG | |
39 | static constexpr int32_t kMaxIntFracSig = 999; | |
40 | ||
41 | // ICU4J Equivalent: RoundingUtils.DEFAULT_ROUNDING_MODE | |
42 | static constexpr RoundingMode kDefaultMode = RoundingMode::UNUM_FOUND_HALFEVEN; | |
43 | ||
44 | // ICU4J Equivalent: Padder.FALLBACK_PADDING_STRING | |
45 | static constexpr char16_t kFallbackPaddingString[] = u" "; | |
46 | ||
47 | // Forward declarations: | |
48 | ||
49 | class Modifier; | |
50 | class MutablePatternModifier; | |
51 | class DecimalQuantity; | |
52 | class NumberStringBuilder; | |
3d1f044b | 53 | class ModifierStore; |
0f5d89e8 A |
54 | struct MicroProps; |
55 | ||
56 | ||
57 | enum AffixPatternType { | |
58 | // Represents a literal character; the value is stored in the code point field. | |
59 | TYPE_CODEPOINT = 0, | |
60 | ||
61 | // Represents a minus sign symbol '-'. | |
62 | TYPE_MINUS_SIGN = -1, | |
63 | ||
64 | // Represents a plus sign symbol '+'. | |
65 | TYPE_PLUS_SIGN = -2, | |
66 | ||
67 | // Represents a percent sign symbol '%'. | |
68 | TYPE_PERCENT = -3, | |
69 | ||
70 | // Represents a permille sign symbol '‰'. | |
71 | TYPE_PERMILLE = -4, | |
72 | ||
73 | // Represents a single currency symbol '¤'. | |
74 | TYPE_CURRENCY_SINGLE = -5, | |
75 | ||
76 | // Represents a double currency symbol '¤¤'. | |
77 | TYPE_CURRENCY_DOUBLE = -6, | |
78 | ||
79 | // Represents a triple currency symbol '¤¤¤'. | |
80 | TYPE_CURRENCY_TRIPLE = -7, | |
81 | ||
82 | // Represents a quadruple currency symbol '¤¤¤¤'. | |
83 | TYPE_CURRENCY_QUAD = -8, | |
84 | ||
85 | // Represents a quintuple currency symbol '¤¤¤¤¤'. | |
86 | TYPE_CURRENCY_QUINT = -9, | |
87 | ||
88 | // Represents a sequence of six or more currency symbols. | |
89 | TYPE_CURRENCY_OVERFLOW = -15 | |
90 | }; | |
91 | ||
92 | enum CompactType { | |
93 | TYPE_DECIMAL, TYPE_CURRENCY | |
94 | }; | |
95 | ||
96 | ||
97 | class U_I18N_API AffixPatternProvider { | |
98 | public: | |
99 | static const int32_t AFFIX_PLURAL_MASK = 0xff; | |
100 | static const int32_t AFFIX_PREFIX = 0x100; | |
101 | static const int32_t AFFIX_NEGATIVE_SUBPATTERN = 0x200; | |
102 | static const int32_t AFFIX_PADDING = 0x400; | |
103 | ||
104 | // Convenience compound flags | |
105 | static const int32_t AFFIX_POS_PREFIX = AFFIX_PREFIX; | |
106 | static const int32_t AFFIX_POS_SUFFIX = 0; | |
107 | static const int32_t AFFIX_NEG_PREFIX = AFFIX_PREFIX | AFFIX_NEGATIVE_SUBPATTERN; | |
108 | static const int32_t AFFIX_NEG_SUFFIX = AFFIX_NEGATIVE_SUBPATTERN; | |
109 | ||
110 | virtual ~AffixPatternProvider(); | |
111 | ||
112 | virtual char16_t charAt(int flags, int i) const = 0; | |
113 | ||
114 | virtual int length(int flags) const = 0; | |
115 | ||
116 | virtual UnicodeString getString(int flags) const = 0; | |
117 | ||
118 | virtual bool hasCurrencySign() const = 0; | |
119 | ||
120 | virtual bool positiveHasPlusSign() const = 0; | |
121 | ||
122 | virtual bool hasNegativeSubpattern() const = 0; | |
123 | ||
124 | virtual bool negativeHasMinusSign() const = 0; | |
125 | ||
126 | virtual bool containsSymbolType(AffixPatternType, UErrorCode&) const = 0; | |
127 | ||
128 | /** | |
129 | * True if the pattern has a number placeholder like "0" or "#,##0.00"; false if the pattern does not | |
130 | * have one. This is used in cases like compact notation, where the pattern replaces the entire | |
131 | * number instead of rendering the number. | |
132 | */ | |
133 | virtual bool hasBody() const = 0; | |
134 | }; | |
135 | ||
3d1f044b | 136 | |
0f5d89e8 A |
137 | /** |
138 | * A Modifier is an object that can be passed through the formatting pipeline until it is finally applied to the string | |
139 | * builder. A Modifier usually contains a prefix and a suffix that are applied, but it could contain something else, | |
140 | * like a {@link com.ibm.icu.text.SimpleFormatter} pattern. | |
141 | * | |
3d1f044b | 142 | * A Modifier is usually immutable, except in cases such as {@link MutablePatternModifier}, which are mutable for performance |
0f5d89e8 A |
143 | * reasons. |
144 | * | |
145 | * Exported as U_I18N_API because it is a base class for other exported types | |
146 | */ | |
147 | class U_I18N_API Modifier { | |
148 | public: | |
149 | virtual ~Modifier(); | |
150 | ||
151 | /** | |
152 | * Apply this Modifier to the string builder. | |
153 | * | |
154 | * @param output | |
155 | * The string builder to which to apply this modifier. | |
156 | * @param leftIndex | |
157 | * The left index of the string within the builder. Equal to 0 when only one number is being formatted. | |
158 | * @param rightIndex | |
159 | * The right index of the string within the string builder. Equal to length when only one number is being | |
160 | * formatted. | |
161 | * @return The number of characters (UTF-16 code units) that were added to the string builder. | |
162 | */ | |
163 | virtual int32_t apply(NumberStringBuilder& output, int leftIndex, int rightIndex, | |
164 | UErrorCode& status) const = 0; | |
165 | ||
166 | /** | |
167 | * Gets the length of the prefix. This information can be used in combination with {@link #apply} to extract the | |
168 | * prefix and suffix strings. | |
169 | * | |
170 | * @return The number of characters (UTF-16 code units) in the prefix. | |
171 | */ | |
3d1f044b | 172 | virtual int32_t getPrefixLength() const = 0; |
0f5d89e8 A |
173 | |
174 | /** | |
175 | * Returns the number of code points in the modifier, prefix plus suffix. | |
176 | */ | |
3d1f044b | 177 | virtual int32_t getCodePointCount() const = 0; |
0f5d89e8 A |
178 | |
179 | /** | |
180 | * Whether this modifier is strong. If a modifier is strong, it should always be applied immediately and not allowed | |
181 | * to bubble up. With regard to padding, strong modifiers are considered to be on the inside of the prefix and | |
182 | * suffix. | |
183 | * | |
184 | * @return Whether the modifier is strong. | |
185 | */ | |
186 | virtual bool isStrong() const = 0; | |
3d1f044b A |
187 | |
188 | /** | |
189 | * Whether the modifier contains at least one occurrence of the given field. | |
190 | */ | |
191 | virtual bool containsField(UNumberFormatFields field) const = 0; | |
192 | ||
193 | /** | |
194 | * A fill-in for getParameters(). obj will always be set; if non-null, the other | |
195 | * two fields are also safe to read. | |
196 | */ | |
197 | struct U_I18N_API Parameters { | |
198 | const ModifierStore* obj = nullptr; | |
199 | int8_t signum; | |
200 | StandardPlural::Form plural; | |
201 | ||
202 | Parameters(); | |
203 | Parameters(const ModifierStore* _obj, int8_t _signum, StandardPlural::Form _plural); | |
204 | }; | |
205 | ||
206 | /** | |
207 | * Gets a set of "parameters" for this Modifier. | |
208 | * | |
209 | * TODO: Make this return a `const Parameters*` more like Java? | |
210 | */ | |
211 | virtual void getParameters(Parameters& output) const = 0; | |
212 | ||
213 | /** | |
214 | * Returns whether this Modifier is *semantically equivalent* to the other Modifier; | |
215 | * in many cases, this is the same as equal, but parameters should be ignored. | |
216 | */ | |
217 | virtual bool semanticallyEquivalent(const Modifier& other) const = 0; | |
0f5d89e8 A |
218 | }; |
219 | ||
3d1f044b A |
220 | |
221 | /** | |
222 | * This is *not* a modifier; rather, it is an object that can return modifiers | |
223 | * based on given parameters. | |
224 | * | |
225 | * Exported as U_I18N_API because it is a base class for other exported types. | |
226 | */ | |
227 | class U_I18N_API ModifierStore { | |
228 | public: | |
229 | virtual ~ModifierStore(); | |
230 | ||
231 | /** | |
232 | * Returns a Modifier with the given parameters (best-effort). | |
233 | */ | |
234 | virtual const Modifier* getModifier(int8_t signum, StandardPlural::Form plural) const = 0; | |
235 | }; | |
236 | ||
237 | ||
0f5d89e8 A |
238 | /** |
239 | * This interface is used when all number formatting settings, including the locale, are known, except for the quantity | |
240 | * itself. The {@link #processQuantity} method performs the final step in the number processing pipeline: it uses the | |
241 | * quantity to generate a finalized {@link MicroProps}, which can be used to render the number to output. | |
242 | * | |
243 | * <p> | |
244 | * In other words, this interface is used for the parts of number processing that are <em>quantity-dependent</em>. | |
245 | * | |
246 | * <p> | |
247 | * In order to allow for multiple different objects to all mutate the same MicroProps, a "chain" of MicroPropsGenerators | |
248 | * are linked together, and each one is responsible for manipulating a certain quantity-dependent part of the | |
249 | * MicroProps. At the tail of the linked list is a base instance of {@link MicroProps} with properties that are not | |
250 | * quantity-dependent. Each element in the linked list calls {@link #processQuantity} on its "parent", then does its | |
251 | * work, and then returns the result. | |
252 | * | |
253 | * Exported as U_I18N_API because it is a base class for other exported types | |
254 | * | |
255 | */ | |
256 | class U_I18N_API MicroPropsGenerator { | |
257 | public: | |
258 | virtual ~MicroPropsGenerator(); | |
259 | ||
260 | /** | |
261 | * Considers the given {@link DecimalQuantity}, optionally mutates it, and returns a {@link MicroProps}. | |
262 | * | |
263 | * @param quantity | |
264 | * The quantity for consideration and optional mutation. | |
265 | * @param micros | |
266 | * The MicroProps instance to populate. | |
267 | * @return A MicroProps instance resolved for the quantity. | |
268 | */ | |
269 | virtual void processQuantity(DecimalQuantity& quantity, MicroProps& micros, | |
270 | UErrorCode& status) const = 0; | |
271 | }; | |
272 | ||
273 | /** | |
274 | * An interface used by compact notation and scientific notation to choose a multiplier while rounding. | |
275 | */ | |
276 | class MultiplierProducer { | |
277 | public: | |
278 | virtual ~MultiplierProducer(); | |
279 | ||
280 | /** | |
281 | * Maps a magnitude to a multiplier in powers of ten. For example, in compact notation in English, a magnitude of 5 | |
282 | * (e.g., 100,000) should return a multiplier of -3, since the number is displayed in thousands. | |
283 | * | |
284 | * @param magnitude | |
285 | * The power of ten of the input number. | |
286 | * @return The shift in powers of ten. | |
287 | */ | |
288 | virtual int32_t getMultiplier(int32_t magnitude) const = 0; | |
289 | }; | |
290 | ||
291 | // Exported as U_I18N_API because it is a public member field of exported DecimalFormatProperties | |
292 | template<typename T> | |
293 | class U_I18N_API NullableValue { | |
294 | public: | |
295 | NullableValue() | |
296 | : fNull(true) {} | |
297 | ||
298 | NullableValue(const NullableValue<T>& other) = default; | |
299 | ||
300 | explicit NullableValue(const T& other) { | |
301 | fValue = other; | |
302 | fNull = false; | |
303 | } | |
304 | ||
305 | NullableValue<T>& operator=(const NullableValue<T>& other) { | |
306 | fNull = other.fNull; | |
307 | if (!fNull) { | |
308 | fValue = other.fValue; | |
309 | } | |
310 | return *this; | |
311 | } | |
312 | ||
313 | NullableValue<T>& operator=(const T& other) { | |
314 | fValue = other; | |
315 | fNull = false; | |
316 | return *this; | |
317 | } | |
318 | ||
319 | bool operator==(const NullableValue& other) const { | |
320 | // "fValue == other.fValue" returns UBool, not bool (causes compiler warnings) | |
321 | return fNull ? other.fNull : (other.fNull ? false : static_cast<bool>(fValue == other.fValue)); | |
322 | } | |
323 | ||
324 | void nullify() { | |
325 | // TODO: It might be nice to call the destructor here. | |
326 | fNull = true; | |
327 | } | |
328 | ||
329 | bool isNull() const { | |
330 | return fNull; | |
331 | } | |
332 | ||
333 | T get(UErrorCode& status) const { | |
334 | if (fNull) { | |
335 | status = U_UNDEFINED_VARIABLE; | |
336 | } | |
337 | return fValue; | |
338 | } | |
339 | ||
340 | T getNoError() const { | |
341 | return fValue; | |
342 | } | |
343 | ||
344 | T getOrDefault(T defaultValue) const { | |
345 | return fNull ? defaultValue : fValue; | |
346 | } | |
347 | ||
348 | private: | |
349 | bool fNull; | |
350 | T fValue; | |
351 | }; | |
352 | ||
3d1f044b | 353 | |
0f5d89e8 A |
354 | } // namespace impl |
355 | } // namespace number | |
356 | U_NAMESPACE_END | |
357 | ||
358 | #endif //__NUMBER_TYPES_H__ | |
359 | ||
360 | #endif /* #if !UCONFIG_NO_FORMATTING */ |