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_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: |
| 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 Chang | d8aa9d5 | 2021-01-05 23:49:57 +0000 | [diff] [blame] | 40 | bool containsField(Field field) const U_OVERRIDE; |
Victor Chang | 7322950 | 2020-09-17 13:39:19 +0100 | [diff] [blame] | 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 | |
Victor Chang | d8aa9d5 | 2021-01-05 23:49:57 +0000 | [diff] [blame] | 76 | bool containsField(Field field) const U_OVERRIDE; |
Victor Chang | 7322950 | 2020-09-17 13:39:19 +0100 | [diff] [blame] | 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: |
| 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 Chang | d8aa9d5 | 2021-01-05 23:49:57 +0000 | [diff] [blame] | 169 | bool containsField(Field field) const U_OVERRIDE; |
Victor Chang | 7322950 | 2020-09-17 13:39:19 +0100 | [diff] [blame] | 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: |
| 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 Chang | d8aa9d5 | 2021-01-05 23:49:57 +0000 | [diff] [blame] | 258 | bool containsField(Field field) const U_OVERRIDE { |
Victor Chang | 7322950 | 2020-09-17 13:39:19 +0100 | [diff] [blame] | 259 | (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 | */ |
| 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 | */ |
| 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 Chang | d8aa9d5 | 2021-01-05 23:49:57 +0000 | [diff] [blame] | 322 | const Modifier *mods[4 * StandardPlural::COUNT] = {}; |
Victor Chang | 7322950 | 2020-09-17 13:39:19 +0100 | [diff] [blame] | 323 | |
| 324 | inline static int32_t getModIndex(Signum signum, StandardPlural::Form plural) { |
Victor Chang | d8aa9d5 | 2021-01-05 23:49:57 +0000 | [diff] [blame] | 325 | U_ASSERT(signum >= 0 && signum < SIGNUM_COUNT); |
Victor Chang | 7322950 | 2020-09-17 13:39:19 +0100 | [diff] [blame] | 326 | U_ASSERT(plural >= 0 && plural < StandardPlural::COUNT); |
Victor Chang | d8aa9d5 | 2021-01-05 23:49:57 +0000 | [diff] [blame] | 327 | return static_cast<int32_t>(plural) * SIGNUM_COUNT + signum; |
Victor Chang | 7322950 | 2020-09-17 13:39:19 +0100 | [diff] [blame] | 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 */ |