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