blob: 5ba842d5692460a44d053d78c7e6a7e7eb15202a [file] [log] [blame]
Victor Chang73229502020-09-17 13:39:19 +01001// © 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_PATTERNMODIFIER_H__
8#define __NUMBER_PATTERNMODIFIER_H__
9
10#include "standardplural.h"
11#include "unicode/numberformatter.h"
12#include "number_patternstring.h"
13#include "number_types.h"
14#include "number_modifiers.h"
15#include "number_utils.h"
16#include "number_currencysymbols.h"
17
18U_NAMESPACE_BEGIN
19
20// Export an explicit template instantiation of the LocalPointer that is used as a
21// data member of AdoptingModifierStore.
22// (When building DLLs for Windows this is required.)
23#if U_PF_WINDOWS <= U_PLATFORM && U_PLATFORM <= U_PF_CYGWIN
24#if defined(_MSC_VER)
25// Ignore warning 4661 as LocalPointerBase does not use operator== or operator!=
26#pragma warning(push)
27#pragma warning(disable : 4661)
28#endif
29template class U_I18N_API LocalPointerBase<number::impl::AdoptingModifierStore>;
30template class U_I18N_API LocalPointer<number::impl::AdoptingModifierStore>;
31#if defined(_MSC_VER)
32#pragma warning(pop)
33#endif
34#endif
35
36namespace number {
37namespace impl {
38
39// Forward declaration
40class MutablePatternModifier;
41
42// Exported as U_I18N_API because it is needed for the unit test PatternModifierTest
43class U_I18N_API ImmutablePatternModifier : public MicroPropsGenerator, public UMemory {
44 public:
45 ~ImmutablePatternModifier() U_OVERRIDE = default;
46
47 void processQuantity(DecimalQuantity&, MicroProps& micros, UErrorCode& status) const U_OVERRIDE;
48
49 void applyToMicros(MicroProps& micros, const DecimalQuantity& quantity, UErrorCode& status) const;
50
51 const Modifier* getModifier(Signum signum, StandardPlural::Form plural) const;
52
Victor Changd8aa9d52021-01-05 23:49:57 +000053 // Non-const method:
54 void addToChain(const MicroPropsGenerator* parent);
55
Victor Chang73229502020-09-17 13:39:19 +010056 private:
Victor Changd8aa9d52021-01-05 23:49:57 +000057 ImmutablePatternModifier(AdoptingModifierStore* pm, const PluralRules* rules);
Victor Chang73229502020-09-17 13:39:19 +010058
59 const LocalPointer<AdoptingModifierStore> pm;
60 const PluralRules* rules;
61 const MicroPropsGenerator* parent;
62
63 friend class MutablePatternModifier;
64};
65
66/**
67 * This class is a {@link Modifier} that wraps a decimal format pattern. It applies the pattern's affixes in
68 * {@link Modifier#apply}.
69 *
70 * <p>
71 * In addition to being a Modifier, this class contains the business logic for substituting the correct locale symbols
72 * into the affixes of the decimal format pattern.
73 *
74 * <p>
75 * In order to use this class, create a new instance and call the following four setters: {@link #setPatternInfo},
76 * {@link #setPatternAttributes}, {@link #setSymbols}, and {@link #setNumberProperties}. After calling these four
77 * setters, the instance will be ready for use as a Modifier.
78 *
79 * <p>
80 * This is a MUTABLE, NON-THREAD-SAFE class designed for performance. Do NOT save references to this or attempt to use
81 * it from multiple threads! Instead, you can obtain a safe, immutable decimal format pattern modifier by calling
82 * {@link MutablePatternModifier#createImmutable}, in effect treating this instance as a builder for the immutable
83 * variant.
84 */
85class U_I18N_API MutablePatternModifier
86 : public MicroPropsGenerator,
87 public Modifier,
88 public SymbolProvider,
89 public UMemory {
90 public:
91
92 ~MutablePatternModifier() U_OVERRIDE = default;
93
94 /**
95 * @param isStrong
96 * Whether the modifier should be considered strong. For more information, see
97 * {@link Modifier#isStrong()}. Most of the time, decimal format pattern modifiers should be considered
98 * as non-strong.
99 */
100 explicit MutablePatternModifier(bool isStrong);
101
102 /**
103 * Sets a reference to the parsed decimal format pattern, usually obtained from
104 * {@link PatternStringParser#parseToPatternInfo(String)}, but any implementation of {@link AffixPatternProvider} is
105 * accepted.
106 *
107 * @param field
108 * Which field to use for literal characters in the pattern.
109 */
110 void setPatternInfo(const AffixPatternProvider *patternInfo, Field field);
111
112 /**
113 * Sets attributes that imply changes to the literal interpretation of the pattern string affixes.
114 *
115 * @param signDisplay
116 * Whether to force a plus sign on positive numbers.
117 * @param perMille
118 * Whether to substitute the percent sign in the pattern with a permille sign.
119 */
120 void setPatternAttributes(UNumberSignDisplay signDisplay, bool perMille);
121
122 /**
123 * Sets locale-specific details that affect the symbols substituted into the pattern string affixes.
124 *
125 * @param symbols
126 * The desired instance of DecimalFormatSymbols.
Victor Changd8aa9d52021-01-05 23:49:57 +0000127 * @param currency
128 * The currency to be used when substituting currency values into the affixes.
Victor Chang73229502020-09-17 13:39:19 +0100129 * @param unitWidth
130 * The width used to render currencies.
131 * @param rules
132 * Required if the triple currency sign, "¤¤¤", appears in the pattern, which can be determined from the
133 * convenience method {@link #needsPlurals()}.
Victor Changd8aa9d52021-01-05 23:49:57 +0000134 * @param status
135 * Set if an error occurs while loading currency data.
Victor Chang73229502020-09-17 13:39:19 +0100136 */
Victor Changd8aa9d52021-01-05 23:49:57 +0000137 void setSymbols(const DecimalFormatSymbols* symbols, const CurrencyUnit& currency,
138 UNumberUnitWidth unitWidth, const PluralRules* rules, UErrorCode& status);
Victor Chang73229502020-09-17 13:39:19 +0100139
140 /**
141 * Sets attributes of the current number being processed.
142 *
143 * @param signum
144 * -1 if negative; +1 if positive; or 0 if zero.
145 * @param plural
146 * The plural form of the number, required only if the pattern contains the triple
147 * currency sign, "¤¤¤" (and as indicated by {@link #needsPlurals()}).
148 */
149 void setNumberProperties(Signum signum, StandardPlural::Form plural);
150
151 /**
152 * Returns true if the pattern represented by this MurkyModifier requires a plural keyword in order to localize.
153 * This is currently true only if there is a currency long name placeholder in the pattern ("¤¤¤").
154 */
155 bool needsPlurals() const;
156
157 /**
158 * Creates a new quantity-dependent Modifier that behaves the same as the current instance, but which is immutable
159 * and can be saved for future use. The number properties in the current instance are mutated; all other properties
160 * are left untouched.
161 *
162 * <p>
163 * The resulting modifier cannot be used in a QuantityChain.
164 *
165 * <p>
166 * CREATES A NEW HEAP OBJECT; THE CALLER GETS OWNERSHIP.
167 *
168 * @return An immutable that supports both positive and negative numbers.
169 */
170 ImmutablePatternModifier *createImmutable(UErrorCode &status);
171
Victor Chang73229502020-09-17 13:39:19 +0100172 MicroPropsGenerator &addToChain(const MicroPropsGenerator *parent);
173
174 void processQuantity(DecimalQuantity &, MicroProps &micros, UErrorCode &status) const U_OVERRIDE;
175
176 int32_t apply(FormattedStringBuilder &output, int32_t leftIndex, int32_t rightIndex,
177 UErrorCode &status) const U_OVERRIDE;
178
179 int32_t getPrefixLength() const U_OVERRIDE;
180
181 int32_t getCodePointCount() const U_OVERRIDE;
182
183 bool isStrong() const U_OVERRIDE;
184
Victor Changd8aa9d52021-01-05 23:49:57 +0000185 bool containsField(Field field) const U_OVERRIDE;
Victor Chang73229502020-09-17 13:39:19 +0100186
187 void getParameters(Parameters& output) const U_OVERRIDE;
188
189 bool semanticallyEquivalent(const Modifier& other) const U_OVERRIDE;
190
191 /**
192 * Returns the string that substitutes a given symbol type in a pattern.
193 */
194 UnicodeString getSymbol(AffixPatternType type) const U_OVERRIDE;
195
196 UnicodeString toUnicodeString() const;
197
198 private:
199 // Modifier details (initialized in constructor)
200 const bool fStrong;
201
202 // Pattern details (initialized in setPatternInfo and setPatternAttributes)
203 const AffixPatternProvider *fPatternInfo;
204 Field fField;
205 UNumberSignDisplay fSignDisplay;
206 bool fPerMilleReplacesPercent;
207
208 // Symbol details (initialized in setSymbols)
209 const DecimalFormatSymbols *fSymbols;
210 UNumberUnitWidth fUnitWidth;
Victor Changd8aa9d52021-01-05 23:49:57 +0000211 CurrencySymbols fCurrencySymbols;
Victor Chang73229502020-09-17 13:39:19 +0100212 const PluralRules *fRules;
213
214 // Number details (initialized in setNumberProperties)
215 Signum fSignum;
216 StandardPlural::Form fPlural;
217
218 // QuantityChain details (initialized in addToChain)
219 const MicroPropsGenerator *fParent;
220
221 // Transient fields for rendering
222 UnicodeString currentAffix;
223
224 /**
225 * Uses the current properties to create a single {@link ConstantMultiFieldModifier} with currency spacing support
226 * if required.
227 *
228 * <p>
229 * CREATES A NEW HEAP OBJECT; THE CALLER GETS OWNERSHIP.
230 *
231 * @param a
232 * A working FormattedStringBuilder object; passed from the outside to prevent the need to create many new
233 * instances if this method is called in a loop.
234 * @param b
235 * Another working FormattedStringBuilder object.
236 * @return The constant modifier object.
237 */
238 ConstantMultiFieldModifier *createConstantModifier(UErrorCode &status);
239
240 int32_t insertPrefix(FormattedStringBuilder &sb, int position, UErrorCode &status);
241
242 int32_t insertSuffix(FormattedStringBuilder &sb, int position, UErrorCode &status);
243
244 void prepareAffix(bool isPrefix);
245};
246
247
248} // namespace impl
249} // namespace number
250U_NAMESPACE_END
251
252#endif //__NUMBER_PATTERNMODIFIER_H__
253
254#endif /* #if !UCONFIG_NO_FORMATTING */