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