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