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 19 namespace number::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 override; 33 34 int32_t getPrefixLength() const override; 35 36 int32_t getCodePointCount() const override; 37 38 bool isStrong() const override; 39 40 bool containsField(Field field) const override; 41 42 void getParameters(Parameters& output) const override; 43 44 bool strictEquals(const Modifier& other) const 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 override; 69 70 int32_t getPrefixLength() const override; 71 72 int32_t getCodePointCount() const override; 73 74 bool isStrong() const override; 75 76 bool containsField(Field field) const override; 77 78 void getParameters(Parameters& output) const override; 79 80 bool strictEquals(const Modifier& other) const 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 override; 162 163 int32_t getPrefixLength() const override; 164 165 int32_t getCodePointCount() const override; 166 167 bool isStrong() const override; 168 169 bool containsField(Field field) const override; 170 171 void getParameters(Parameters& output) const override; 172 173 bool strictEquals(const Modifier& other) const 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 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 override { 239 (void)output; 240 (void)leftIndex; 241 (void)rightIndex; 242 (void)status; 243 return 0; 244 } 245 getPrefixLength()246 int32_t getPrefixLength() const override { 247 return 0; 248 } 249 getCodePointCount()250 int32_t getCodePointCount() const override { 251 return 0; 252 } 253 isStrong()254 bool isStrong() const override { 255 return fStrong; 256 } 257 containsField(Field field)258 bool containsField(Field field) const override { 259 (void)field; 260 return false; 261 } 262 getParameters(Parameters & output)263 void getParameters(Parameters& output) const override { 264 output.obj = nullptr; 265 } 266 strictEquals(const Modifier & other)267 bool strictEquals(const Modifier& other) const override { 268 return other.getCodePointCount() == 0; 269 } 270 271 private: 272 bool fStrong; 273 }; 274 275 /** An adopting Modifier store that varies by signum but not plural form. */ 276 class U_I18N_API AdoptingSignumModifierStore : public UMemory { 277 public: 278 virtual ~AdoptingSignumModifierStore(); 279 280 AdoptingSignumModifierStore() = default; 281 282 // No copying! 283 AdoptingSignumModifierStore(const AdoptingSignumModifierStore &other) = delete; 284 AdoptingSignumModifierStore& operator=(const AdoptingSignumModifierStore& other) = delete; 285 286 // Moving is OK AdoptingSignumModifierStore(AdoptingSignumModifierStore && other)287 AdoptingSignumModifierStore(AdoptingSignumModifierStore &&other) noexcept { 288 *this = std::move(other); 289 } 290 AdoptingSignumModifierStore& operator=(AdoptingSignumModifierStore&& other) noexcept; 291 292 /** Take ownership of the Modifier and slot it in at the given Signum. */ adoptModifier(Signum signum,const Modifier * mod)293 void adoptModifier(Signum signum, const Modifier* mod) { 294 U_ASSERT(mods[signum] == nullptr); 295 mods[signum] = mod; 296 } 297 298 inline const Modifier*& operator[](Signum signum) { 299 return mods[signum]; 300 } 301 inline Modifier const* operator[](Signum signum) const { 302 return mods[signum]; 303 } 304 305 private: 306 const Modifier* mods[SIGNUM_COUNT] = {}; 307 }; 308 309 /** 310 * This implementation of ModifierStore adopts Modifier pointers. 311 */ 312 class U_I18N_API AdoptingModifierStore : public ModifierStore, public UMemory { 313 public: 314 static constexpr StandardPlural::Form DEFAULT_STANDARD_PLURAL = StandardPlural::OTHER; 315 316 AdoptingModifierStore() = default; 317 318 // No copying! 319 AdoptingModifierStore(const AdoptingModifierStore &other) = delete; 320 321 // Moving is OK 322 AdoptingModifierStore(AdoptingModifierStore &&other) = default; 323 324 /** Sets the modifiers for a specific plural form. */ adoptSignumModifierStore(StandardPlural::Form plural,AdoptingSignumModifierStore other)325 void adoptSignumModifierStore(StandardPlural::Form plural, AdoptingSignumModifierStore other) { 326 mods[plural] = std::move(other); 327 } 328 329 /** Sets the modifiers for the default plural form. */ adoptSignumModifierStoreNoPlural(AdoptingSignumModifierStore other)330 void adoptSignumModifierStoreNoPlural(AdoptingSignumModifierStore other) { 331 mods[DEFAULT_STANDARD_PLURAL] = std::move(other); 332 } 333 334 /** Returns a reference to the modifier; no ownership change. */ getModifier(Signum signum,StandardPlural::Form plural)335 const Modifier *getModifier(Signum signum, StandardPlural::Form plural) const override { 336 const Modifier* modifier = mods[plural][signum]; 337 if (modifier == nullptr && plural != DEFAULT_STANDARD_PLURAL) { 338 modifier = mods[DEFAULT_STANDARD_PLURAL][signum]; 339 } 340 return modifier; 341 } 342 343 /** Returns a reference to the modifier; no ownership change. */ getModifierWithoutPlural(Signum signum)344 const Modifier *getModifierWithoutPlural(Signum signum) const { 345 return mods[DEFAULT_STANDARD_PLURAL][signum]; 346 } 347 348 private: 349 // NOTE: mods is zero-initialized (to nullptr) 350 AdoptingSignumModifierStore mods[StandardPlural::COUNT] = {}; 351 }; 352 353 } // namespace number::impl 354 U_NAMESPACE_END 355 356 357 #endif //__NUMBER_MODIFIERS_H__ 358 359 #endif /* #if !UCONFIG_NO_FORMATTING */ 360