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 "formatted_string_builder.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:
ConstantAffixModifier(const UnicodeString & prefix,const UnicodeString & suffix,Field field,bool strong)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 
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 
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 
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 
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 
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  */
136 class U_I18N_API ConstantMultiFieldModifier : public Modifier, public UMemory {
137   public:
ConstantMultiFieldModifier(const FormattedStringBuilder & prefix,const FormattedStringBuilder & suffix,bool overwrite,bool strong,const Modifier::Parameters parameters)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 
ConstantMultiFieldModifier(const FormattedStringBuilder & prefix,const FormattedStringBuilder & suffix,bool overwrite,bool strong)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 
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 
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. */
186 class 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. */
233 class U_I18N_API EmptyModifier : public Modifier, public UMemory {
234   public:
EmptyModifier(bool isStrong)235     explicit EmptyModifier(bool isStrong) : fStrong(isStrong) {}
236 
apply(FormattedStringBuilder & output,int32_t leftIndex,int32_t rightIndex,UErrorCode & status)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 
getPrefixLength()246     int32_t getPrefixLength() const U_OVERRIDE {
247         return 0;
248     }
249 
getCodePointCount()250     int32_t getCodePointCount() const U_OVERRIDE {
251         return 0;
252     }
253 
isStrong()254     bool isStrong() const U_OVERRIDE {
255         return fStrong;
256     }
257 
containsField(UNumberFormatFields field)258     bool containsField(UNumberFormatFields field) const U_OVERRIDE {
259         (void)field;
260         return false;
261     }
262 
getParameters(Parameters & output)263     void getParameters(Parameters& output) const U_OVERRIDE {
264         output.obj = nullptr;
265     }
266 
semanticallyEquivalent(const Modifier & other)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  */
278 class 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      */
adoptModifier(Signum signum,StandardPlural::Form plural,const Modifier * mod)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      */
adoptModifierWithoutPlural(Signum signum,const Modifier * mod)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. */
getModifier(Signum signum,StandardPlural::Form plural)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. */
getModifierWithoutPlural(Signum signum)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)
322     const Modifier *mods[3 * StandardPlural::COUNT] = {};
323 
getModIndex(Signum signum,StandardPlural::Form plural)324     inline static int32_t getModIndex(Signum signum, StandardPlural::Form plural) {
325         U_ASSERT(signum >= -1 && signum <= 1);
326         U_ASSERT(plural >= 0 && plural < StandardPlural::COUNT);
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 */
339