Home | History | Annotate | Download | only in i18n
      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_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 
     19 U_NAMESPACE_BEGIN
     20 namespace number {
     21 namespace impl {
     22 
     23 // Typedef several enums for brevity and for easier comparison to Java.
     24 
     25 typedef UNumberFormatFields Field;
     26 
     27 typedef UNumberFormatRoundingMode RoundingMode;
     28 
     29 typedef UNumberFormatPadPosition PadPosition;
     30 
     31 typedef UNumberCompactStyle CompactStyle;
     32 
     33 // ICU4J Equivalent: RoundingUtils.MAX_INT_FRAC_SIG
     34 static constexpr int32_t kMaxIntFracSig = 100;
     35 
     36 // ICU4J Equivalent: RoundingUtils.DEFAULT_ROUNDING_MODE
     37 static constexpr RoundingMode kDefaultMode = RoundingMode::UNUM_FOUND_HALFEVEN;
     38 
     39 // ICU4J Equivalent: Padder.FALLBACK_PADDING_STRING
     40 static constexpr char16_t kFallbackPaddingString[] = u" ";
     41 
     42 // ICU4J Equivalent: NumberFormatterImpl.DEFAULT_CURRENCY
     43 static constexpr char16_t kDefaultCurrency[] = u"XXX";
     44 
     45 // FIXME: New error codes:
     46 static constexpr UErrorCode U_NUMBER_DIGIT_WIDTH_OUTOFBOUNDS_ERROR = U_ILLEGAL_ARGUMENT_ERROR;
     47 static constexpr UErrorCode U_NUMBER_PADDING_WIDTH_OUTOFBOUNDS_ERROR = U_ILLEGAL_ARGUMENT_ERROR;
     48 
     49 // Forward declarations:
     50 
     51 class Modifier;
     52 class MutablePatternModifier;
     53 class DecimalQuantity;
     54 class NumberStringBuilder;
     55 struct MicroProps;
     56 
     57 
     58 enum AffixPatternType {
     59     // Represents a literal character; the value is stored in the code point field.
     60             TYPE_CODEPOINT = 0,
     61 
     62     // Represents a minus sign symbol '-'.
     63             TYPE_MINUS_SIGN = -1,
     64 
     65     // Represents a plus sign symbol '+'.
     66             TYPE_PLUS_SIGN = -2,
     67 
     68     // Represents a percent sign symbol '%'.
     69             TYPE_PERCENT = -3,
     70 
     71     // Represents a permille sign symbol ''.
     72             TYPE_PERMILLE = -4,
     73 
     74     // Represents a single currency symbol ''.
     75             TYPE_CURRENCY_SINGLE = -5,
     76 
     77     // Represents a double currency symbol ''.
     78             TYPE_CURRENCY_DOUBLE = -6,
     79 
     80     // Represents a triple currency symbol ''.
     81             TYPE_CURRENCY_TRIPLE = -7,
     82 
     83     // Represents a quadruple currency symbol ''.
     84             TYPE_CURRENCY_QUAD = -8,
     85 
     86     // Represents a quintuple currency symbol ''.
     87             TYPE_CURRENCY_QUINT = -9,
     88 
     89     // Represents a sequence of six or more currency symbols.
     90             TYPE_CURRENCY_OVERFLOW = -15
     91 };
     92 
     93 enum CompactType {
     94     TYPE_DECIMAL,
     95     TYPE_CURRENCY
     96 };
     97 
     98 
     99 // TODO: Should this be moved somewhere else, maybe where other ICU classes can use it?
    100 // Exported as U_I18N_API because it is a base class for other exported types
    101 class U_I18N_API CharSequence {
    102 public:
    103     virtual ~CharSequence() = default;
    104 
    105     virtual int32_t length() const = 0;
    106 
    107     virtual char16_t charAt(int32_t index) const = 0;
    108 
    109     virtual UChar32 codePointAt(int32_t index) const {
    110         // Default implementation; can be overridden with a more efficient version
    111         char16_t leading = charAt(index);
    112         if (U16_IS_LEAD(leading) && length() > index + 1) {
    113             char16_t trailing = charAt(index + 1);
    114             return U16_GET_SUPPLEMENTARY(leading, trailing);
    115         } else {
    116             return leading;
    117         }
    118     }
    119 
    120     virtual UnicodeString toUnicodeString() const = 0;
    121 };
    122 
    123 class U_I18N_API AffixPatternProvider {
    124   public:
    125     static const int32_t AFFIX_PLURAL_MASK = 0xff;
    126     static const int32_t AFFIX_PREFIX = 0x100;
    127     static const int32_t AFFIX_NEGATIVE_SUBPATTERN = 0x200;
    128     static const int32_t AFFIX_PADDING = 0x400;
    129 
    130     virtual ~AffixPatternProvider() = default;
    131 
    132     virtual char16_t charAt(int flags, int i) const = 0;
    133 
    134     virtual int length(int flags) const = 0;
    135 
    136     virtual bool hasCurrencySign() const = 0;
    137 
    138     virtual bool positiveHasPlusSign() const = 0;
    139 
    140     virtual bool hasNegativeSubpattern() const = 0;
    141 
    142     virtual bool negativeHasMinusSign() const = 0;
    143 
    144     virtual bool containsSymbolType(AffixPatternType, UErrorCode &) const = 0;
    145 };
    146 
    147 /**
    148  * A Modifier is an object that can be passed through the formatting pipeline until it is finally applied to the string
    149  * builder. A Modifier usually contains a prefix and a suffix that are applied, but it could contain something else,
    150  * like a {@link com.ibm.icu.text.SimpleFormatter} pattern.
    151  *
    152  * A Modifier is usually immutable, except in cases such as {@link MurkyModifier}, which are mutable for performance
    153  * reasons.
    154  *
    155  * Exported as U_I18N_API because it is a base class for other exported types
    156  */
    157 class U_I18N_API Modifier {
    158   public:
    159     virtual ~Modifier() = default;
    160 
    161     /**
    162      * Apply this Modifier to the string builder.
    163      *
    164      * @param output
    165      *            The string builder to which to apply this modifier.
    166      * @param leftIndex
    167      *            The left index of the string within the builder. Equal to 0 when only one number is being formatted.
    168      * @param rightIndex
    169      *            The right index of the string within the string builder. Equal to length when only one number is being
    170      *            formatted.
    171      * @return The number of characters (UTF-16 code units) that were added to the string builder.
    172      */
    173     virtual int32_t
    174     apply(NumberStringBuilder &output, int leftIndex, int rightIndex, UErrorCode &status) const = 0;
    175 
    176     /**
    177      * Gets the length of the prefix. This information can be used in combination with {@link #apply} to extract the
    178      * prefix and suffix strings.
    179      *
    180      * @return The number of characters (UTF-16 code units) in the prefix.
    181      */
    182     virtual int32_t getPrefixLength(UErrorCode& status) const = 0;
    183 
    184     /**
    185      * Returns the number of code points in the modifier, prefix plus suffix.
    186      */
    187     virtual int32_t getCodePointCount(UErrorCode &status) const = 0;
    188 
    189     /**
    190      * Whether this modifier is strong. If a modifier is strong, it should always be applied immediately and not allowed
    191      * to bubble up. With regard to padding, strong modifiers are considered to be on the inside of the prefix and
    192      * suffix.
    193      *
    194      * @return Whether the modifier is strong.
    195      */
    196     virtual bool isStrong() const = 0;
    197 };
    198 
    199 /**
    200  * This interface is used when all number formatting settings, including the locale, are known, except for the quantity
    201  * itself. The {@link #processQuantity} method performs the final step in the number processing pipeline: it uses the
    202  * quantity to generate a finalized {@link MicroProps}, which can be used to render the number to output.
    203  *
    204  * <p>
    205  * In other words, this interface is used for the parts of number processing that are <em>quantity-dependent</em>.
    206  *
    207  * <p>
    208  * In order to allow for multiple different objects to all mutate the same MicroProps, a "chain" of MicroPropsGenerators
    209  * are linked together, and each one is responsible for manipulating a certain quantity-dependent part of the
    210  * MicroProps. At the tail of the linked list is a base instance of {@link MicroProps} with properties that are not
    211  * quantity-dependent. Each element in the linked list calls {@link #processQuantity} on its "parent", then does its
    212  * work, and then returns the result.
    213  *
    214  * Exported as U_I18N_API because it is a base class for other exported types
    215  *
    216  */
    217 class U_I18N_API MicroPropsGenerator {
    218   public:
    219     virtual ~MicroPropsGenerator() = default;
    220 
    221     /**
    222      * Considers the given {@link DecimalQuantity}, optionally mutates it, and returns a {@link MicroProps}.
    223      *
    224      * @param quantity
    225      *            The quantity for consideration and optional mutation.
    226      * @param micros
    227      *            The MicroProps instance to populate.
    228      * @return A MicroProps instance resolved for the quantity.
    229      */
    230     virtual void processQuantity(DecimalQuantity& quantity, MicroProps& micros, UErrorCode& status) const = 0;
    231 };
    232 
    233 class MultiplierProducer {
    234   public:
    235     virtual ~MultiplierProducer() = default;
    236 
    237     virtual int32_t getMultiplier(int32_t magnitude) const = 0;
    238 };
    239 
    240 // Exported as U_I18N_API because it is a public member field of exported DecimalFormatProperties
    241 template<typename T>
    242 class U_I18N_API NullableValue {
    243   public:
    244     NullableValue() : fNull(true) {}
    245 
    246     NullableValue(const NullableValue<T> &other) = default;
    247 
    248     explicit NullableValue(const T &other) {
    249         fValue = other;
    250         fNull = false;
    251     }
    252 
    253     NullableValue<T> &operator=(const NullableValue<T> &other) = default;
    254 
    255     NullableValue<T> &operator=(const T &other) {
    256         fValue = other;
    257         fNull = false;
    258         return *this;
    259     }
    260 
    261     bool operator==(const NullableValue &other) const {
    262         // "fValue == other.fValue" returns UBool, not bool (causes compiler warnings)
    263         return fNull ? other.fNull : (other.fNull ? false : static_cast<bool>(fValue == other.fValue));
    264     }
    265 
    266     void nullify() {
    267         // TODO: It might be nice to call the destructor here.
    268         fNull = true;
    269     }
    270 
    271     bool isNull() const {
    272         return fNull;
    273     }
    274 
    275     T get(UErrorCode &status) const {
    276         if (fNull) {
    277             status = U_UNDEFINED_VARIABLE;
    278         }
    279         return fValue;
    280     }
    281 
    282   private:
    283     bool fNull;
    284     T fValue;
    285 };
    286 
    287 } // namespace impl
    288 } // namespace number
    289 U_NAMESPACE_END
    290 
    291 #endif //__NUMBER_TYPES_H__
    292 
    293 #endif /* #if !UCONFIG_NO_FORMATTING */
    294