blob: 375254310ca0564f412fdc8bd2e8bf2e65ed3ef0 [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_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 "formatted_string_builder.h"
16#include "number_types.h"
17
18U_NAMESPACE_BEGIN namespace number {
19namespace 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 */
25class 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(FormattedStringBuilder &output, int32_t leftIndex, int32_t rightIndex,
32 UErrorCode &status) const U_OVERRIDE;
33
34 int32_t getPrefixLength() const U_OVERRIDE;
35
36 int32_t getCodePointCount() const U_OVERRIDE;
37
38 bool isStrong() const U_OVERRIDE;
39
Victor Changd8aa9d52021-01-05 23:49:57 +000040 bool containsField(Field field) const U_OVERRIDE;
Victor Chang73229502020-09-17 13:39:19 +010041
42 void getParameters(Parameters& output) const U_OVERRIDE;
43
44 bool semanticallyEquivalent(const Modifier& other) const U_OVERRIDE;
45
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 */
57class U_I18N_API SimpleModifier : public Modifier, public UMemory {
58 public:
59 SimpleModifier(const SimpleFormatter &simpleFormatter, Field field, bool strong);
60
61 SimpleModifier(const SimpleFormatter &simpleFormatter, Field field, bool strong,
62 const Modifier::Parameters parameters);
63
64 // Default constructor for LongNameHandler.h
65 SimpleModifier();
66
67 int32_t apply(FormattedStringBuilder &output, int32_t leftIndex, int32_t rightIndex,
68 UErrorCode &status) const U_OVERRIDE;
69
70 int32_t getPrefixLength() const U_OVERRIDE;
71
72 int32_t getCodePointCount() const U_OVERRIDE;
73
74 bool isStrong() const U_OVERRIDE;
75
Victor Changd8aa9d52021-01-05 23:49:57 +000076 bool containsField(Field field) const U_OVERRIDE;
Victor Chang73229502020-09-17 13:39:19 +010077
78 void getParameters(Parameters& output) const U_OVERRIDE;
79
80 bool semanticallyEquivalent(const Modifier& other) const U_OVERRIDE;
81
82 /**
83 * TODO: This belongs in SimpleFormatterImpl. The only reason I haven't moved it there yet is because
84 * FormattedStringBuilder is an internal class and SimpleFormatterImpl feels like it should not depend on it.
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
103 formatAsPrefixSuffix(FormattedStringBuilder& 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 FormattedStringBuilder are near each other.
109 *
110 * <p>
111 * Applies the compiled two-argument pattern to the FormattedStringBuilder.
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, FormattedStringBuilder& result,
119 int32_t index, int32_t* outPrefixLength, int32_t* outSuffixLength,
120 Field field, UErrorCode& status);
121
122 private:
123 UnicodeString fCompiledPattern;
124 Field fField;
125 bool fStrong = false;
126 int32_t fPrefixLength = 0;
127 int32_t fSuffixOffset = -1;
128 int32_t fSuffixLength = 0;
129 Modifier::Parameters fParameters;
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 FormattedStringBuilder} instances (one for the prefix, one for the suffix).
135 */
136class U_I18N_API ConstantMultiFieldModifier : public Modifier, public UMemory {
137 public:
138 ConstantMultiFieldModifier(
139 const FormattedStringBuilder &prefix,
140 const FormattedStringBuilder &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
150 ConstantMultiFieldModifier(
151 const FormattedStringBuilder &prefix,
152 const FormattedStringBuilder &suffix,
153 bool overwrite,
154 bool strong)
155 : fPrefix(prefix),
156 fSuffix(suffix),
157 fOverwrite(overwrite),
158 fStrong(strong) {}
159
160 int32_t apply(FormattedStringBuilder &output, int32_t leftIndex, int32_t rightIndex,
161 UErrorCode &status) const U_OVERRIDE;
162
163 int32_t getPrefixLength() const U_OVERRIDE;
164
165 int32_t getCodePointCount() const U_OVERRIDE;
166
167 bool isStrong() const U_OVERRIDE;
168
Victor Changd8aa9d52021-01-05 23:49:57 +0000169 bool containsField(Field field) const U_OVERRIDE;
Victor Chang73229502020-09-17 13:39:19 +0100170
171 void getParameters(Parameters& output) const U_OVERRIDE;
172
173 bool semanticallyEquivalent(const Modifier& other) const U_OVERRIDE;
174
175 protected:
176 // NOTE: In Java, these are stored as array pointers. In C++, the FormattedStringBuilder is stored by
177 // value and is treated internally as immutable.
178 FormattedStringBuilder fPrefix;
179 FormattedStringBuilder fSuffix;
180 bool fOverwrite;
181 bool fStrong;
182 Modifier::Parameters fParameters;
183};
184
185/** Identical to {@link ConstantMultiFieldModifier}, but supports currency spacing. */
186class U_I18N_API CurrencySpacingEnabledModifier : public ConstantMultiFieldModifier {
187 public:
188 /** Safe code path */
189 CurrencySpacingEnabledModifier(
190 const FormattedStringBuilder &prefix,
191 const FormattedStringBuilder &suffix,
192 bool overwrite,
193 bool strong,
194 const DecimalFormatSymbols &symbols,
195 UErrorCode &status);
196
197 int32_t apply(FormattedStringBuilder &output, int32_t leftIndex, int32_t rightIndex,
198 UErrorCode &status) const U_OVERRIDE;
199
200 /** Unsafe code path */
201 static int32_t
202 applyCurrencySpacing(FormattedStringBuilder &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(FormattedStringBuilder &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. */
233class U_I18N_API EmptyModifier : public Modifier, public UMemory {
234 public:
235 explicit EmptyModifier(bool isStrong) : fStrong(isStrong) {}
236
237 int32_t apply(FormattedStringBuilder &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
246 int32_t getPrefixLength() const U_OVERRIDE {
247 return 0;
248 }
249
250 int32_t getCodePointCount() const U_OVERRIDE {
251 return 0;
252 }
253
254 bool isStrong() const U_OVERRIDE {
255 return fStrong;
256 }
257
Victor Changd8aa9d52021-01-05 23:49:57 +0000258 bool containsField(Field field) const U_OVERRIDE {
Victor Chang73229502020-09-17 13:39:19 +0100259 (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
271 private:
272 bool fStrong;
273};
274
275/**
276 * This implementation of ModifierStore adopts Modifer pointers.
277 */
278class U_I18N_API AdoptingModifierStore : public ModifierStore, public UMemory {
279 public:
280 virtual ~AdoptingModifierStore();
281
282 static constexpr StandardPlural::Form DEFAULT_STANDARD_PLURAL = StandardPlural::OTHER;
283
284 AdoptingModifierStore() = default;
285
286 // No copying!
287 AdoptingModifierStore(const AdoptingModifierStore &other) = delete;
288
289 /**
290 * Sets the Modifier with the specified signum and plural form.
291 */
292 void adoptModifier(Signum signum, StandardPlural::Form plural, const Modifier *mod) {
293 U_ASSERT(mods[getModIndex(signum, plural)] == nullptr);
294 mods[getModIndex(signum, plural)] = mod;
295 }
296
297 /**
298 * Sets the Modifier with the specified signum.
299 * The modifier will apply to all plural forms.
300 */
301 void adoptModifierWithoutPlural(Signum signum, const Modifier *mod) {
302 U_ASSERT(mods[getModIndex(signum, DEFAULT_STANDARD_PLURAL)] == nullptr);
303 mods[getModIndex(signum, DEFAULT_STANDARD_PLURAL)] = mod;
304 }
305
306 /** Returns a reference to the modifier; no ownership change. */
307 const Modifier *getModifier(Signum 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;
313 }
314
315 /** Returns a reference to the modifier; no ownership change. */
316 const Modifier *getModifierWithoutPlural(Signum signum) const {
317 return mods[getModIndex(signum, DEFAULT_STANDARD_PLURAL)];
318 }
319
320 private:
321 // NOTE: mods is zero-initialized (to nullptr)
Victor Changd8aa9d52021-01-05 23:49:57 +0000322 const Modifier *mods[4 * StandardPlural::COUNT] = {};
Victor Chang73229502020-09-17 13:39:19 +0100323
324 inline static int32_t getModIndex(Signum signum, StandardPlural::Form plural) {
Victor Changd8aa9d52021-01-05 23:49:57 +0000325 U_ASSERT(signum >= 0 && signum < SIGNUM_COUNT);
Victor Chang73229502020-09-17 13:39:19 +0100326 U_ASSERT(plural >= 0 && plural < StandardPlural::COUNT);
Victor Changd8aa9d52021-01-05 23:49:57 +0000327 return static_cast<int32_t>(plural) * SIGNUM_COUNT + signum;
Victor Chang73229502020-09-17 13:39:19 +0100328 }
329};
330
331} // namespace impl
332} // namespace number
333U_NAMESPACE_END
334
335
336#endif //__NUMBER_MODIFIERS_H__
337
338#endif /* #if !UCONFIG_NO_FORMATTING */