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