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 "number_stringbuilder.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: 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(NumberStringBuilder &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 40 bool containsField(UNumberFormatFields field) const U_OVERRIDE; 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(NumberStringBuilder &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 76 bool containsField(UNumberFormatFields field) const U_OVERRIDE; 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 * NumberStringBuilder 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(NumberStringBuilder& result, int32_t startIndex, int32_t endIndex, Field field, 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 NumberStringBuilder are near each other. 109 * 110 * <p> 111 * Applies the compiled two-argument pattern to the NumberStringBuilder. 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, NumberStringBuilder& 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 NumberStringBuilder} instances (one for the prefix, one for the suffix). 135 */ 136 class U_I18N_API ConstantMultiFieldModifier : public Modifier, public UMemory { 137 public: ConstantMultiFieldModifier(const NumberStringBuilder & prefix,const NumberStringBuilder & suffix,bool overwrite,bool strong,const Modifier::Parameters parameters)138 ConstantMultiFieldModifier( 139 const NumberStringBuilder &prefix, 140 const NumberStringBuilder &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 NumberStringBuilder & prefix,const NumberStringBuilder & suffix,bool overwrite,bool strong)150 ConstantMultiFieldModifier( 151 const NumberStringBuilder &prefix, 152 const NumberStringBuilder &suffix, 153 bool overwrite, 154 bool strong) 155 : fPrefix(prefix), 156 fSuffix(suffix), 157 fOverwrite(overwrite), 158 fStrong(strong) {} 159 160 int32_t apply(NumberStringBuilder &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 169 bool containsField(UNumberFormatFields field) const U_OVERRIDE; 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 NumberStringBuilder is stored by 177 // value and is treated internally as immutable. 178 NumberStringBuilder fPrefix; 179 NumberStringBuilder 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 NumberStringBuilder &prefix, 191 const NumberStringBuilder &suffix, 192 bool overwrite, 193 bool strong, 194 const DecimalFormatSymbols &symbols, 195 UErrorCode &status); 196 197 int32_t apply(NumberStringBuilder &output, int32_t leftIndex, int32_t rightIndex, 198 UErrorCode &status) const U_OVERRIDE; 199 200 /** Unsafe code path */ 201 static int32_t 202 applyCurrencySpacing(NumberStringBuilder &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(NumberStringBuilder &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(NumberStringBuilder & output,int32_t leftIndex,int32_t rightIndex,UErrorCode & status)237 int32_t apply(NumberStringBuilder &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 getPrefixLength()246 int32_t getPrefixLength() const U_OVERRIDE { 247 return 0; 248 } 249 getCodePointCount()250 int32_t getCodePointCount() const U_OVERRIDE { 251 return 0; 252 } 253 isStrong()254 bool isStrong() const U_OVERRIDE { 255 return fStrong; 256 } 257 containsField(UNumberFormatFields field)258 bool containsField(UNumberFormatFields field) const U_OVERRIDE { 259 (void)field; 260 return false; 261 } 262 getParameters(Parameters & output)263 void getParameters(Parameters& output) const U_OVERRIDE { 264 output.obj = nullptr; 265 } 266 semanticallyEquivalent(const Modifier & other)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 */ adoptModifier(int8_t signum,StandardPlural::Form plural,const Modifier * mod)292 void adoptModifier(int8_t 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 */ adoptModifierWithoutPlural(int8_t signum,const Modifier * mod)301 void adoptModifierWithoutPlural(int8_t 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. */ getModifier(int8_t signum,StandardPlural::Form plural)307 const Modifier *getModifier(int8_t 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. */ getModifierWithoutPlural(int8_t signum)316 const Modifier *getModifierWithoutPlural(int8_t signum) const { 317 return mods[getModIndex(signum, DEFAULT_STANDARD_PLURAL)]; 318 } 319 320 private: 321 // NOTE: mods is zero-initialized (to nullptr) 322 const Modifier *mods[3 * StandardPlural::COUNT] = {}; 323 getModIndex(int8_t signum,StandardPlural::Form plural)324 inline static int32_t getModIndex(int8_t signum, StandardPlural::Form plural) { 325 U_ASSERT(signum >= -1 && signum <= 1); 326 U_ASSERT(plural >= 0 && plural < StandardPlural::COUNT); 327 return static_cast<int32_t>(plural) * 3 + (signum + 1); 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 */ 339