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 && !UPRV_INCOMPLETE_CPP11_SUPPORT 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: 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(UErrorCode &status) const U_OVERRIDE; 35 36 int32_t getCodePointCount(UErrorCode &status) const U_OVERRIDE; 37 38 bool isStrong() const U_OVERRIDE; 39 40 private: 41 UnicodeString fPrefix; 42 UnicodeString fSuffix; 43 Field fField; 44 bool fStrong; 45 }; 46 47 /** 48 * The second primary implementation of {@link Modifier}, this one consuming a {@link SimpleFormatter} 49 * pattern. 50 */ 51 class U_I18N_API SimpleModifier : public Modifier, public UMemory { 52 public: 53 SimpleModifier(const SimpleFormatter &simpleFormatter, Field field, bool strong); 54 55 // Default constructor for LongNameHandler.h 56 SimpleModifier(); 57 58 int32_t apply(NumberStringBuilder &output, int32_t leftIndex, int32_t rightIndex, 59 UErrorCode &status) const U_OVERRIDE; 60 61 int32_t getPrefixLength(UErrorCode &status) const U_OVERRIDE; 62 63 int32_t getCodePointCount(UErrorCode &status) const U_OVERRIDE; 64 65 bool isStrong() const U_OVERRIDE; 66 67 /** 68 * TODO: This belongs in SimpleFormatterImpl. The only reason I haven't moved it there yet is because 69 * DoubleSidedStringBuilder is an internal class and SimpleFormatterImpl feels like it should not depend on it. 70 * 71 * <p> 72 * Formats a value that is already stored inside the StringBuilder <code>result</code> between the indices 73 * <code>startIndex</code> and <code>endIndex</code> by inserting characters before the start index and after the 74 * end index. 75 * 76 * <p> 77 * This is well-defined only for patterns with exactly one argument. 78 * 79 * @param result 80 * The StringBuilder containing the value argument. 81 * @param startIndex 82 * The left index of the value within the string builder. 83 * @param endIndex 84 * The right index of the value within the string builder. 85 * @return The number of characters (UTF-16 code points) that were added to the StringBuilder. 86 */ 87 int32_t 88 formatAsPrefixSuffix(NumberStringBuilder &result, int32_t startIndex, int32_t endIndex, Field field, 89 UErrorCode &status) const; 90 91 private: 92 UnicodeString fCompiledPattern; 93 Field fField; 94 bool fStrong; 95 int32_t fPrefixLength; 96 int32_t fSuffixOffset; 97 int32_t fSuffixLength; 98 }; 99 100 /** 101 * An implementation of {@link Modifier} that allows for multiple types of fields in the same modifier. Constructed 102 * based on the contents of two {@link NumberStringBuilder} instances (one for the prefix, one for the suffix). 103 */ 104 class U_I18N_API ConstantMultiFieldModifier : public Modifier, public UMemory { 105 public: 106 ConstantMultiFieldModifier(const NumberStringBuilder &prefix, const NumberStringBuilder &suffix, 107 bool strong) : fPrefix(prefix), fSuffix(suffix), fStrong(strong) {} 108 109 int32_t apply(NumberStringBuilder &output, int32_t leftIndex, int32_t rightIndex, 110 UErrorCode &status) const U_OVERRIDE; 111 112 int32_t getPrefixLength(UErrorCode &status) const U_OVERRIDE; 113 114 int32_t getCodePointCount(UErrorCode &status) const U_OVERRIDE; 115 116 bool isStrong() const U_OVERRIDE; 117 118 protected: 119 // NOTE: In Java, these are stored as array pointers. In C++, the NumberStringBuilder is stored by 120 // value and is treated internally as immutable. 121 NumberStringBuilder fPrefix; 122 NumberStringBuilder fSuffix; 123 bool fStrong; 124 }; 125 126 /** Identical to {@link ConstantMultiFieldModifier}, but supports currency spacing. */ 127 class U_I18N_API CurrencySpacingEnabledModifier : public ConstantMultiFieldModifier { 128 public: 129 /** Safe code path */ 130 CurrencySpacingEnabledModifier(const NumberStringBuilder &prefix, const NumberStringBuilder &suffix, 131 bool strong, const DecimalFormatSymbols &symbols, UErrorCode &status); 132 133 int32_t apply(NumberStringBuilder &output, int32_t leftIndex, int32_t rightIndex, 134 UErrorCode &status) const U_OVERRIDE; 135 136 /** Unsafe code path */ 137 static int32_t 138 applyCurrencySpacing(NumberStringBuilder &output, int32_t prefixStart, int32_t prefixLen, 139 int32_t suffixStart, int32_t suffixLen, const DecimalFormatSymbols &symbols, 140 UErrorCode &status); 141 142 private: 143 UnicodeSet fAfterPrefixUnicodeSet; 144 UnicodeString fAfterPrefixInsert; 145 UnicodeSet fBeforeSuffixUnicodeSet; 146 UnicodeString fBeforeSuffixInsert; 147 148 enum EAffix { 149 PREFIX, SUFFIX 150 }; 151 152 enum EPosition { 153 IN_CURRENCY, IN_NUMBER 154 }; 155 156 /** Unsafe code path */ 157 static int32_t applyCurrencySpacingAffix(NumberStringBuilder &output, int32_t index, EAffix affix, 158 const DecimalFormatSymbols &symbols, UErrorCode &status); 159 160 static UnicodeSet 161 getUnicodeSet(const DecimalFormatSymbols &symbols, EPosition position, EAffix affix, 162 UErrorCode &status); 163 164 static UnicodeString 165 getInsertString(const DecimalFormatSymbols &symbols, EAffix affix, UErrorCode &status); 166 }; 167 168 /** A Modifier that does not do anything. */ 169 class U_I18N_API EmptyModifier : public Modifier, public UMemory { 170 public: 171 explicit EmptyModifier(bool isStrong) : fStrong(isStrong) {} 172 173 int32_t apply(NumberStringBuilder &output, int32_t leftIndex, int32_t rightIndex, 174 UErrorCode &status) const U_OVERRIDE { 175 (void)output; 176 (void)leftIndex; 177 (void)rightIndex; 178 (void)status; 179 return 0; 180 } 181 182 int32_t getPrefixLength(UErrorCode &status) const U_OVERRIDE { 183 (void)status; 184 return 0; 185 } 186 187 int32_t getCodePointCount(UErrorCode &status) const U_OVERRIDE { 188 (void)status; 189 return 0; 190 } 191 192 bool isStrong() const U_OVERRIDE { 193 return fStrong; 194 } 195 196 private: 197 bool fStrong; 198 }; 199 200 /** 201 * A ParameterizedModifier by itself is NOT a Modifier. Rather, it wraps a data structure containing two or more 202 * Modifiers and returns the modifier appropriate for the current situation. 203 */ 204 class U_I18N_API ParameterizedModifier : public UMemory { 205 public: 206 // NOTE: mods is zero-initialized (to nullptr) 207 ParameterizedModifier() : mods() { 208 } 209 210 // No copying! 211 ParameterizedModifier(const ParameterizedModifier &other) = delete; 212 213 ~ParameterizedModifier() { 214 for (const Modifier *mod : mods) { 215 delete mod; 216 } 217 } 218 219 void adoptPositiveNegativeModifiers(const Modifier *positive, const Modifier *negative) { 220 mods[0] = positive; 221 mods[1] = negative; 222 } 223 224 /** The modifier is ADOPTED. */ 225 void adoptSignPluralModifier(bool isNegative, StandardPlural::Form plural, const Modifier *mod) { 226 mods[getModIndex(isNegative, plural)] = mod; 227 } 228 229 /** Returns a reference to the modifier; no ownership change. */ 230 const Modifier *getModifier(bool isNegative) const { 231 return mods[isNegative ? 1 : 0]; 232 } 233 234 /** Returns a reference to the modifier; no ownership change. */ 235 const Modifier *getModifier(bool isNegative, StandardPlural::Form plural) const { 236 return mods[getModIndex(isNegative, plural)]; 237 } 238 239 private: 240 const Modifier *mods[2 * StandardPlural::COUNT]; 241 242 inline static int32_t getModIndex(bool isNegative, StandardPlural::Form plural) { 243 return static_cast<int32_t>(plural) * 2 + (isNegative ? 1 : 0); 244 } 245 }; 246 247 } // namespace impl 248 } // namespace number 249 U_NAMESPACE_END 250 251 252 #endif //__NUMBER_MODIFIERS_H__ 253 254 #endif /* #if !UCONFIG_NO_FORMATTING */ 255