]>
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_MODIFIERS_H__ | |
8 | #define __NUMBER_MODIFIERS_H__ | |
9 | ||
10 | #include <algorithm> | |
11 | #include <cstdint> | |
12 | #include "unicode/uniset.h" | |
13 | #include "unicode/simpleformatter.h" | |
14 | #include "standardplural.h" | |
15 | #include "number_stringbuilder.h" | |
16 | #include "number_types.h" | |
17 | ||
18 | U_NAMESPACE_BEGIN namespace number { | |
19 | namespace impl { | |
20 | ||
21 | /** | |
22 | * The canonical implementation of {@link Modifier}, containing a prefix and suffix string. | |
23 | * TODO: This is not currently being used by real code and could be removed. | |
24 | */ | |
25 | class U_I18N_API ConstantAffixModifier : public Modifier, public UObject { | |
26 | public: | |
27 | ConstantAffixModifier(const UnicodeString &prefix, const UnicodeString &suffix, Field field, | |
28 | bool strong) | |
29 | : fPrefix(prefix), fSuffix(suffix), fField(field), fStrong(strong) {} | |
30 | ||
31 | int32_t apply(NumberStringBuilder &output, int32_t leftIndex, int32_t rightIndex, | |
32 | UErrorCode &status) const U_OVERRIDE; | |
33 | ||
3d1f044b | 34 | int32_t getPrefixLength() const U_OVERRIDE; |
0f5d89e8 | 35 | |
3d1f044b | 36 | int32_t getCodePointCount() const U_OVERRIDE; |
0f5d89e8 A |
37 | |
38 | bool isStrong() const U_OVERRIDE; | |
39 | ||
3d1f044b A |
40 | bool containsField(UNumberFormatFields field) const U_OVERRIDE; |
41 | ||
42 | void getParameters(Parameters& output) const U_OVERRIDE; | |
43 | ||
44 | bool semanticallyEquivalent(const Modifier& other) const U_OVERRIDE; | |
45 | ||
0f5d89e8 A |
46 | private: |
47 | UnicodeString fPrefix; | |
48 | UnicodeString fSuffix; | |
49 | Field fField; | |
50 | bool fStrong; | |
51 | }; | |
52 | ||
53 | /** | |
54 | * The second primary implementation of {@link Modifier}, this one consuming a {@link SimpleFormatter} | |
55 | * pattern. | |
56 | */ | |
57 | class U_I18N_API SimpleModifier : public Modifier, public UMemory { | |
58 | public: | |
59 | SimpleModifier(const SimpleFormatter &simpleFormatter, Field field, bool strong); | |
60 | ||
3d1f044b A |
61 | SimpleModifier(const SimpleFormatter &simpleFormatter, Field field, bool strong, |
62 | const Modifier::Parameters parameters); | |
63 | ||
0f5d89e8 A |
64 | // Default constructor for LongNameHandler.h |
65 | SimpleModifier(); | |
66 | ||
67 | int32_t apply(NumberStringBuilder &output, int32_t leftIndex, int32_t rightIndex, | |
68 | UErrorCode &status) const U_OVERRIDE; | |
69 | ||
3d1f044b | 70 | int32_t getPrefixLength() const U_OVERRIDE; |
0f5d89e8 | 71 | |
3d1f044b | 72 | int32_t getCodePointCount() const U_OVERRIDE; |
0f5d89e8 A |
73 | |
74 | bool isStrong() const U_OVERRIDE; | |
75 | ||
3d1f044b A |
76 | bool containsField(UNumberFormatFields field) const U_OVERRIDE; |
77 | ||
78 | void getParameters(Parameters& output) const U_OVERRIDE; | |
79 | ||
80 | bool semanticallyEquivalent(const Modifier& other) const U_OVERRIDE; | |
81 | ||
0f5d89e8 A |
82 | /** |
83 | * TODO: This belongs in SimpleFormatterImpl. The only reason I haven't moved it there yet is because | |
3d1f044b | 84 | * NumberStringBuilder is an internal class and SimpleFormatterImpl feels like it should not depend on it. |
0f5d89e8 A |
85 | * |
86 | * <p> | |
87 | * Formats a value that is already stored inside the StringBuilder <code>result</code> between the indices | |
88 | * <code>startIndex</code> and <code>endIndex</code> by inserting characters before the start index and after the | |
89 | * end index. | |
90 | * | |
91 | * <p> | |
92 | * This is well-defined only for patterns with exactly one argument. | |
93 | * | |
94 | * @param result | |
95 | * The StringBuilder containing the value argument. | |
96 | * @param startIndex | |
97 | * The left index of the value within the string builder. | |
98 | * @param endIndex | |
99 | * The right index of the value within the string builder. | |
100 | * @return The number of characters (UTF-16 code points) that were added to the StringBuilder. | |
101 | */ | |
102 | int32_t | |
3d1f044b A |
103 | formatAsPrefixSuffix(NumberStringBuilder& result, int32_t startIndex, int32_t endIndex, |
104 | UErrorCode& status) const; | |
105 | ||
106 | /** | |
107 | * TODO: Like above, this belongs with the rest of the SimpleFormatterImpl code. | |
108 | * I put it here so that the SimpleFormatter uses in NumberStringBuilder are near each other. | |
109 | * | |
110 | * <p> | |
111 | * Applies the compiled two-argument pattern to the NumberStringBuilder. | |
112 | * | |
113 | * <p> | |
114 | * This method is optimized for the case where the prefix and suffix are often empty, such as | |
115 | * in the range pattern like "{0}-{1}". | |
116 | */ | |
117 | static int32_t | |
118 | formatTwoArgPattern(const SimpleFormatter& compiled, NumberStringBuilder& result, | |
119 | int32_t index, int32_t* outPrefixLength, int32_t* outSuffixLength, | |
120 | Field field, UErrorCode& status); | |
0f5d89e8 A |
121 | |
122 | private: | |
123 | UnicodeString fCompiledPattern; | |
124 | Field fField; | |
3d1f044b A |
125 | bool fStrong = false; |
126 | int32_t fPrefixLength = 0; | |
127 | int32_t fSuffixOffset = -1; | |
128 | int32_t fSuffixLength = 0; | |
129 | Modifier::Parameters fParameters; | |
0f5d89e8 A |
130 | }; |
131 | ||
132 | /** | |
133 | * An implementation of {@link Modifier} that allows for multiple types of fields in the same modifier. Constructed | |
134 | * based on the contents of two {@link NumberStringBuilder} instances (one for the prefix, one for the suffix). | |
135 | */ | |
136 | class U_I18N_API ConstantMultiFieldModifier : public Modifier, public UMemory { | |
137 | public: | |
3d1f044b A |
138 | ConstantMultiFieldModifier( |
139 | const NumberStringBuilder &prefix, | |
140 | const NumberStringBuilder &suffix, | |
141 | bool overwrite, | |
142 | bool strong, | |
143 | const Modifier::Parameters parameters) | |
144 | : fPrefix(prefix), | |
145 | fSuffix(suffix), | |
146 | fOverwrite(overwrite), | |
147 | fStrong(strong), | |
148 | fParameters(parameters) {} | |
149 | ||
0f5d89e8 A |
150 | ConstantMultiFieldModifier( |
151 | const NumberStringBuilder &prefix, | |
152 | const NumberStringBuilder &suffix, | |
153 | bool overwrite, | |
154 | bool strong) | |
155 | : fPrefix(prefix), | |
156 | fSuffix(suffix), | |
157 | fOverwrite(overwrite), | |
158 | fStrong(strong) {} | |
159 | ||
160 | int32_t apply(NumberStringBuilder &output, int32_t leftIndex, int32_t rightIndex, | |
161 | UErrorCode &status) const U_OVERRIDE; | |
162 | ||
3d1f044b | 163 | int32_t getPrefixLength() const U_OVERRIDE; |
0f5d89e8 | 164 | |
3d1f044b | 165 | int32_t getCodePointCount() const U_OVERRIDE; |
0f5d89e8 A |
166 | |
167 | bool isStrong() const U_OVERRIDE; | |
168 | ||
3d1f044b A |
169 | bool containsField(UNumberFormatFields field) const U_OVERRIDE; |
170 | ||
171 | void getParameters(Parameters& output) const U_OVERRIDE; | |
172 | ||
173 | bool semanticallyEquivalent(const Modifier& other) const U_OVERRIDE; | |
174 | ||
0f5d89e8 A |
175 | protected: |
176 | // NOTE: In Java, these are stored as array pointers. In C++, the NumberStringBuilder is stored by | |
177 | // value and is treated internally as immutable. | |
178 | NumberStringBuilder fPrefix; | |
179 | NumberStringBuilder fSuffix; | |
180 | bool fOverwrite; | |
181 | bool fStrong; | |
3d1f044b | 182 | Modifier::Parameters fParameters; |
0f5d89e8 A |
183 | }; |
184 | ||
185 | /** Identical to {@link ConstantMultiFieldModifier}, but supports currency spacing. */ | |
186 | class U_I18N_API CurrencySpacingEnabledModifier : public ConstantMultiFieldModifier { | |
187 | public: | |
188 | /** Safe code path */ | |
189 | CurrencySpacingEnabledModifier( | |
190 | const NumberStringBuilder &prefix, | |
191 | const NumberStringBuilder &suffix, | |
192 | bool overwrite, | |
193 | bool strong, | |
194 | const DecimalFormatSymbols &symbols, | |
195 | UErrorCode &status); | |
196 | ||
197 | int32_t apply(NumberStringBuilder &output, int32_t leftIndex, int32_t rightIndex, | |
198 | UErrorCode &status) const U_OVERRIDE; | |
199 | ||
200 | /** Unsafe code path */ | |
201 | static int32_t | |
202 | applyCurrencySpacing(NumberStringBuilder &output, int32_t prefixStart, int32_t prefixLen, | |
203 | int32_t suffixStart, int32_t suffixLen, const DecimalFormatSymbols &symbols, | |
204 | UErrorCode &status); | |
205 | ||
206 | private: | |
207 | UnicodeSet fAfterPrefixUnicodeSet; | |
208 | UnicodeString fAfterPrefixInsert; | |
209 | UnicodeSet fBeforeSuffixUnicodeSet; | |
210 | UnicodeString fBeforeSuffixInsert; | |
211 | ||
212 | enum EAffix { | |
213 | PREFIX, SUFFIX | |
214 | }; | |
215 | ||
216 | enum EPosition { | |
217 | IN_CURRENCY, IN_NUMBER | |
218 | }; | |
219 | ||
220 | /** Unsafe code path */ | |
221 | static int32_t applyCurrencySpacingAffix(NumberStringBuilder &output, int32_t index, EAffix affix, | |
222 | const DecimalFormatSymbols &symbols, UErrorCode &status); | |
223 | ||
224 | static UnicodeSet | |
225 | getUnicodeSet(const DecimalFormatSymbols &symbols, EPosition position, EAffix affix, | |
226 | UErrorCode &status); | |
227 | ||
228 | static UnicodeString | |
229 | getInsertString(const DecimalFormatSymbols &symbols, EAffix affix, UErrorCode &status); | |
230 | }; | |
231 | ||
232 | /** A Modifier that does not do anything. */ | |
233 | class U_I18N_API EmptyModifier : public Modifier, public UMemory { | |
234 | public: | |
235 | explicit EmptyModifier(bool isStrong) : fStrong(isStrong) {} | |
236 | ||
237 | int32_t apply(NumberStringBuilder &output, int32_t leftIndex, int32_t rightIndex, | |
238 | UErrorCode &status) const U_OVERRIDE { | |
239 | (void)output; | |
240 | (void)leftIndex; | |
241 | (void)rightIndex; | |
242 | (void)status; | |
243 | return 0; | |
244 | } | |
245 | ||
3d1f044b | 246 | int32_t getPrefixLength() const U_OVERRIDE { |
0f5d89e8 A |
247 | return 0; |
248 | } | |
249 | ||
3d1f044b | 250 | int32_t getCodePointCount() const U_OVERRIDE { |
0f5d89e8 A |
251 | return 0; |
252 | } | |
253 | ||
254 | bool isStrong() const U_OVERRIDE { | |
255 | return fStrong; | |
256 | } | |
257 | ||
3d1f044b A |
258 | bool containsField(UNumberFormatFields field) const U_OVERRIDE { |
259 | (void)field; | |
260 | return false; | |
261 | } | |
262 | ||
263 | void getParameters(Parameters& output) const U_OVERRIDE { | |
264 | output.obj = nullptr; | |
265 | } | |
266 | ||
267 | bool semanticallyEquivalent(const Modifier& other) const U_OVERRIDE { | |
268 | return other.getCodePointCount() == 0; | |
269 | } | |
270 | ||
0f5d89e8 A |
271 | private: |
272 | bool fStrong; | |
273 | }; | |
274 | ||
275 | /** | |
3d1f044b | 276 | * This implementation of ModifierStore adopts Modifer pointers. |
0f5d89e8 | 277 | */ |
3d1f044b | 278 | class U_I18N_API AdoptingModifierStore : public ModifierStore, public UMemory { |
0f5d89e8 | 279 | public: |
3d1f044b | 280 | virtual ~AdoptingModifierStore(); |
0f5d89e8 | 281 | |
3d1f044b | 282 | static constexpr StandardPlural::Form DEFAULT_STANDARD_PLURAL = StandardPlural::OTHER; |
0f5d89e8 | 283 | |
3d1f044b | 284 | AdoptingModifierStore() = default; |
0f5d89e8 | 285 | |
3d1f044b A |
286 | // No copying! |
287 | AdoptingModifierStore(const AdoptingModifierStore &other) = delete; | |
0f5d89e8 | 288 | |
3d1f044b A |
289 | /** |
290 | * Sets the Modifier with the specified signum and plural form. | |
291 | */ | |
292 | void adoptModifier(int8_t signum, StandardPlural::Form plural, const Modifier *mod) { | |
293 | U_ASSERT(mods[getModIndex(signum, plural)] == nullptr); | |
0f5d89e8 A |
294 | mods[getModIndex(signum, plural)] = mod; |
295 | } | |
296 | ||
3d1f044b A |
297 | /** |
298 | * Sets the Modifier with the specified signum. | |
299 | * The modifier will apply to all plural forms. | |
300 | */ | |
301 | void adoptModifierWithoutPlural(int8_t signum, const Modifier *mod) { | |
302 | U_ASSERT(mods[getModIndex(signum, DEFAULT_STANDARD_PLURAL)] == nullptr); | |
303 | mods[getModIndex(signum, DEFAULT_STANDARD_PLURAL)] = mod; | |
304 | } | |
305 | ||
0f5d89e8 | 306 | /** Returns a reference to the modifier; no ownership change. */ |
3d1f044b A |
307 | const Modifier *getModifier(int8_t signum, StandardPlural::Form plural) const U_OVERRIDE { |
308 | const Modifier* modifier = mods[getModIndex(signum, plural)]; | |
309 | if (modifier == nullptr && plural != DEFAULT_STANDARD_PLURAL) { | |
310 | modifier = mods[getModIndex(signum, DEFAULT_STANDARD_PLURAL)]; | |
311 | } | |
312 | return modifier; | |
0f5d89e8 A |
313 | } |
314 | ||
315 | /** Returns a reference to the modifier; no ownership change. */ | |
3d1f044b A |
316 | const Modifier *getModifierWithoutPlural(int8_t signum) const { |
317 | return mods[getModIndex(signum, DEFAULT_STANDARD_PLURAL)]; | |
0f5d89e8 A |
318 | } |
319 | ||
320 | private: | |
3d1f044b A |
321 | // NOTE: mods is zero-initialized (to nullptr) |
322 | const Modifier *mods[3 * StandardPlural::COUNT] = {}; | |
0f5d89e8 A |
323 | |
324 | inline static int32_t getModIndex(int8_t signum, StandardPlural::Form plural) { | |
3d1f044b A |
325 | U_ASSERT(signum >= -1 && signum <= 1); |
326 | U_ASSERT(plural >= 0 && plural < StandardPlural::COUNT); | |
0f5d89e8 A |
327 | return static_cast<int32_t>(plural) * 3 + (signum + 1); |
328 | } | |
329 | }; | |
330 | ||
331 | } // namespace impl | |
332 | } // namespace number | |
333 | U_NAMESPACE_END | |
334 | ||
335 | ||
336 | #endif //__NUMBER_MODIFIERS_H__ | |
337 | ||
338 | #endif /* #if !UCONFIG_NO_FORMATTING */ |