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