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