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_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