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_TYPES_H__ 8 #define __NUMBER_TYPES_H__ 9 10 #include <cstdint> 11 #include "unicode/decimfmt.h" 12 #include "unicode/unum.h" 13 #include "unicode/numsys.h" 14 #include "unicode/numberformatter.h" 15 #include "unicode/utf16.h" 16 #include "uassert.h" 17 #include "unicode/platform.h" 18 #include "unicode/uniset.h" 19 #include "standardplural.h" 20 21 U_NAMESPACE_BEGIN namespace number { 22 namespace impl { 23 24 // Typedef several enums for brevity and for easier comparison to Java. 25 26 typedef UNumberFormatFields Field; 27 28 typedef UNumberFormatRoundingMode RoundingMode; 29 30 typedef UNumberFormatPadPosition PadPosition; 31 32 typedef UNumberCompactStyle CompactStyle; 33 34 // ICU4J Equivalent: RoundingUtils.MAX_INT_FRAC_SIG 35 static constexpr int32_t kMaxIntFracSig = 999; 36 37 // ICU4J Equivalent: RoundingUtils.DEFAULT_ROUNDING_MODE 38 static constexpr RoundingMode kDefaultMode = RoundingMode::UNUM_FOUND_HALFEVEN; 39 40 // ICU4J Equivalent: Padder.FALLBACK_PADDING_STRING 41 static constexpr char16_t kFallbackPaddingString[] = u" "; 42 43 // Forward declarations: 44 45 class Modifier; 46 class MutablePatternModifier; 47 class DecimalQuantity; 48 class NumberStringBuilder; 49 class ModifierStore; 50 struct MicroProps; 51 52 53 enum AffixPatternType { 54 // Represents a literal character; the value is stored in the code point field. 55 TYPE_CODEPOINT = 0, 56 57 // Represents a minus sign symbol '-'. 58 TYPE_MINUS_SIGN = -1, 59 60 // Represents a plus sign symbol '+'. 61 TYPE_PLUS_SIGN = -2, 62 63 // Represents a percent sign symbol '%'. 64 TYPE_PERCENT = -3, 65 66 // Represents a permille sign symbol '‰'. 67 TYPE_PERMILLE = -4, 68 69 // Represents a single currency symbol '¤'. 70 TYPE_CURRENCY_SINGLE = -5, 71 72 // Represents a double currency symbol '¤¤'. 73 TYPE_CURRENCY_DOUBLE = -6, 74 75 // Represents a triple currency symbol '¤¤¤'. 76 TYPE_CURRENCY_TRIPLE = -7, 77 78 // Represents a quadruple currency symbol '¤¤¤¤'. 79 TYPE_CURRENCY_QUAD = -8, 80 81 // Represents a quintuple currency symbol '¤¤¤¤¤'. 82 TYPE_CURRENCY_QUINT = -9, 83 84 // Represents a sequence of six or more currency symbols. 85 TYPE_CURRENCY_OVERFLOW = -15 86 }; 87 88 enum CompactType { 89 TYPE_DECIMAL, TYPE_CURRENCY 90 }; 91 92 93 class U_I18N_API AffixPatternProvider { 94 public: 95 static const int32_t AFFIX_PLURAL_MASK = 0xff; 96 static const int32_t AFFIX_PREFIX = 0x100; 97 static const int32_t AFFIX_NEGATIVE_SUBPATTERN = 0x200; 98 static const int32_t AFFIX_PADDING = 0x400; 99 100 // Convenience compound flags 101 static const int32_t AFFIX_POS_PREFIX = AFFIX_PREFIX; 102 static const int32_t AFFIX_POS_SUFFIX = 0; 103 static const int32_t AFFIX_NEG_PREFIX = AFFIX_PREFIX | AFFIX_NEGATIVE_SUBPATTERN; 104 static const int32_t AFFIX_NEG_SUFFIX = AFFIX_NEGATIVE_SUBPATTERN; 105 106 virtual ~AffixPatternProvider(); 107 108 virtual char16_t charAt(int flags, int i) const = 0; 109 110 virtual int length(int flags) const = 0; 111 112 virtual UnicodeString getString(int flags) const = 0; 113 114 virtual bool hasCurrencySign() const = 0; 115 116 virtual bool positiveHasPlusSign() const = 0; 117 118 virtual bool hasNegativeSubpattern() const = 0; 119 120 virtual bool negativeHasMinusSign() const = 0; 121 122 virtual bool containsSymbolType(AffixPatternType, UErrorCode&) const = 0; 123 124 /** 125 * True if the pattern has a number placeholder like "0" or "#,##0.00"; false if the pattern does not 126 * have one. This is used in cases like compact notation, where the pattern replaces the entire 127 * number instead of rendering the number. 128 */ 129 virtual bool hasBody() const = 0; 130 }; 131 132 133 /** 134 * A Modifier is an object that can be passed through the formatting pipeline until it is finally applied to the string 135 * builder. A Modifier usually contains a prefix and a suffix that are applied, but it could contain something else, 136 * like a {@link com.ibm.icu.text.SimpleFormatter} pattern. 137 * 138 * A Modifier is usually immutable, except in cases such as {@link MutablePatternModifier}, which are mutable for performance 139 * reasons. 140 * 141 * Exported as U_I18N_API because it is a base class for other exported types 142 */ 143 class U_I18N_API Modifier { 144 public: 145 virtual ~Modifier(); 146 147 /** 148 * Apply this Modifier to the string builder. 149 * 150 * @param output 151 * The string builder to which to apply this modifier. 152 * @param leftIndex 153 * The left index of the string within the builder. Equal to 0 when only one number is being formatted. 154 * @param rightIndex 155 * The right index of the string within the string builder. Equal to length when only one number is being 156 * formatted. 157 * @return The number of characters (UTF-16 code units) that were added to the string builder. 158 */ 159 virtual int32_t apply(NumberStringBuilder& output, int leftIndex, int rightIndex, 160 UErrorCode& status) const = 0; 161 162 /** 163 * Gets the length of the prefix. This information can be used in combination with {@link #apply} to extract the 164 * prefix and suffix strings. 165 * 166 * @return The number of characters (UTF-16 code units) in the prefix. 167 */ 168 virtual int32_t getPrefixLength() const = 0; 169 170 /** 171 * Returns the number of code points in the modifier, prefix plus suffix. 172 */ 173 virtual int32_t getCodePointCount() const = 0; 174 175 /** 176 * Whether this modifier is strong. If a modifier is strong, it should always be applied immediately and not allowed 177 * to bubble up. With regard to padding, strong modifiers are considered to be on the inside of the prefix and 178 * suffix. 179 * 180 * @return Whether the modifier is strong. 181 */ 182 virtual bool isStrong() const = 0; 183 184 /** 185 * Whether the modifier contains at least one occurrence of the given field. 186 */ 187 virtual bool containsField(UNumberFormatFields field) const = 0; 188 189 /** 190 * A fill-in for getParameters(). obj will always be set; if non-null, the other 191 * two fields are also safe to read. 192 */ 193 struct U_I18N_API Parameters { 194 const ModifierStore* obj = nullptr; 195 int8_t signum; 196 StandardPlural::Form plural; 197 198 Parameters(); 199 Parameters(const ModifierStore* _obj, int8_t _signum, StandardPlural::Form _plural); 200 }; 201 202 /** 203 * Gets a set of "parameters" for this Modifier. 204 * 205 * TODO: Make this return a `const Parameters*` more like Java? 206 */ 207 virtual void getParameters(Parameters& output) const = 0; 208 209 /** 210 * Returns whether this Modifier is *semantically equivalent* to the other Modifier; 211 * in many cases, this is the same as equal, but parameters should be ignored. 212 */ 213 virtual bool semanticallyEquivalent(const Modifier& other) const = 0; 214 }; 215 216 217 /** 218 * This is *not* a modifier; rather, it is an object that can return modifiers 219 * based on given parameters. 220 * 221 * Exported as U_I18N_API because it is a base class for other exported types. 222 */ 223 class U_I18N_API ModifierStore { 224 public: 225 virtual ~ModifierStore(); 226 227 /** 228 * Returns a Modifier with the given parameters (best-effort). 229 */ 230 virtual const Modifier* getModifier(int8_t signum, StandardPlural::Form plural) const = 0; 231 }; 232 233 234 /** 235 * This interface is used when all number formatting settings, including the locale, are known, except for the quantity 236 * itself. The {@link #processQuantity} method performs the final step in the number processing pipeline: it uses the 237 * quantity to generate a finalized {@link MicroProps}, which can be used to render the number to output. 238 * 239 * <p> 240 * In other words, this interface is used for the parts of number processing that are <em>quantity-dependent</em>. 241 * 242 * <p> 243 * In order to allow for multiple different objects to all mutate the same MicroProps, a "chain" of MicroPropsGenerators 244 * are linked together, and each one is responsible for manipulating a certain quantity-dependent part of the 245 * MicroProps. At the tail of the linked list is a base instance of {@link MicroProps} with properties that are not 246 * quantity-dependent. Each element in the linked list calls {@link #processQuantity} on its "parent", then does its 247 * work, and then returns the result. 248 * 249 * Exported as U_I18N_API because it is a base class for other exported types 250 * 251 */ 252 class U_I18N_API MicroPropsGenerator { 253 public: 254 virtual ~MicroPropsGenerator(); 255 256 /** 257 * Considers the given {@link DecimalQuantity}, optionally mutates it, and returns a {@link MicroProps}. 258 * 259 * @param quantity 260 * The quantity for consideration and optional mutation. 261 * @param micros 262 * The MicroProps instance to populate. 263 * @return A MicroProps instance resolved for the quantity. 264 */ 265 virtual void processQuantity(DecimalQuantity& quantity, MicroProps& micros, 266 UErrorCode& status) const = 0; 267 }; 268 269 /** 270 * An interface used by compact notation and scientific notation to choose a multiplier while rounding. 271 */ 272 class MultiplierProducer { 273 public: 274 virtual ~MultiplierProducer(); 275 276 /** 277 * Maps a magnitude to a multiplier in powers of ten. For example, in compact notation in English, a magnitude of 5 278 * (e.g., 100,000) should return a multiplier of -3, since the number is displayed in thousands. 279 * 280 * @param magnitude 281 * The power of ten of the input number. 282 * @return The shift in powers of ten. 283 */ 284 virtual int32_t getMultiplier(int32_t magnitude) const = 0; 285 }; 286 287 // Exported as U_I18N_API because it is a public member field of exported DecimalFormatProperties 288 template<typename T> 289 class U_I18N_API NullableValue { 290 public: NullableValue()291 NullableValue() 292 : fNull(true) {} 293 294 NullableValue(const NullableValue<T>& other) = default; 295 NullableValue(const T & other)296 explicit NullableValue(const T& other) { 297 fValue = other; 298 fNull = false; 299 } 300 301 NullableValue<T>& operator=(const NullableValue<T>& other) { 302 fNull = other.fNull; 303 if (!fNull) { 304 fValue = other.fValue; 305 } 306 return *this; 307 } 308 309 NullableValue<T>& operator=(const T& other) { 310 fValue = other; 311 fNull = false; 312 return *this; 313 } 314 315 bool operator==(const NullableValue& other) const { 316 // "fValue == other.fValue" returns UBool, not bool (causes compiler warnings) 317 return fNull ? other.fNull : (other.fNull ? false : static_cast<bool>(fValue == other.fValue)); 318 } 319 nullify()320 void nullify() { 321 // TODO: It might be nice to call the destructor here. 322 fNull = true; 323 } 324 isNull()325 bool isNull() const { 326 return fNull; 327 } 328 get(UErrorCode & status)329 T get(UErrorCode& status) const { 330 if (fNull) { 331 status = U_UNDEFINED_VARIABLE; 332 } 333 return fValue; 334 } 335 getNoError()336 T getNoError() const { 337 return fValue; 338 } 339 getOrDefault(T defaultValue)340 T getOrDefault(T defaultValue) const { 341 return fNull ? defaultValue : fValue; 342 } 343 344 private: 345 bool fNull; 346 T fValue; 347 }; 348 349 } // namespace impl 350 } // namespace number 351 U_NAMESPACE_END 352 353 #endif //__NUMBER_TYPES_H__ 354 355 #endif /* #if !UCONFIG_NO_FORMATTING */ 356