| // © 2017 and later: Unicode, Inc. and others. |
| // License & terms of use: http://www.unicode.org/copyright.html |
| |
| #include "unicode/utypes.h" |
| |
| #if !UCONFIG_NO_FORMATTING |
| #ifndef __NUMBER_MODIFIERS_H__ |
| #define __NUMBER_MODIFIERS_H__ |
| |
| #include <algorithm> |
| #include <cstdint> |
| #include "unicode/uniset.h" |
| #include "unicode/simpleformatter.h" |
| #include "standardplural.h" |
| #include "formatted_string_builder.h" |
| #include "number_types.h" |
| |
| U_NAMESPACE_BEGIN namespace number { |
| namespace impl { |
| |
| /** |
| * The canonical implementation of {@link Modifier}, containing a prefix and suffix string. |
| * TODO: This is not currently being used by real code and could be removed. |
| */ |
| class U_I18N_API ConstantAffixModifier : public Modifier, public UObject { |
| public: |
| ConstantAffixModifier(const UnicodeString &prefix, const UnicodeString &suffix, Field field, |
| bool strong) |
| : fPrefix(prefix), fSuffix(suffix), fField(field), fStrong(strong) {} |
| |
| int32_t apply(FormattedStringBuilder &output, int32_t leftIndex, int32_t rightIndex, |
| UErrorCode &status) const U_OVERRIDE; |
| |
| int32_t getPrefixLength() const U_OVERRIDE; |
| |
| int32_t getCodePointCount() const U_OVERRIDE; |
| |
| bool isStrong() const U_OVERRIDE; |
| |
| bool containsField(Field field) const U_OVERRIDE; |
| |
| void getParameters(Parameters& output) const U_OVERRIDE; |
| |
| bool semanticallyEquivalent(const Modifier& other) const U_OVERRIDE; |
| |
| private: |
| UnicodeString fPrefix; |
| UnicodeString fSuffix; |
| Field fField; |
| bool fStrong; |
| }; |
| |
| /** |
| * The second primary implementation of {@link Modifier}, this one consuming a {@link SimpleFormatter} |
| * pattern. |
| */ |
| class U_I18N_API SimpleModifier : public Modifier, public UMemory { |
| public: |
| SimpleModifier(const SimpleFormatter &simpleFormatter, Field field, bool strong); |
| |
| SimpleModifier(const SimpleFormatter &simpleFormatter, Field field, bool strong, |
| const Modifier::Parameters parameters); |
| |
| // Default constructor for LongNameHandler.h |
| SimpleModifier(); |
| |
| int32_t apply(FormattedStringBuilder &output, int32_t leftIndex, int32_t rightIndex, |
| UErrorCode &status) const U_OVERRIDE; |
| |
| int32_t getPrefixLength() const U_OVERRIDE; |
| |
| int32_t getCodePointCount() const U_OVERRIDE; |
| |
| bool isStrong() const U_OVERRIDE; |
| |
| bool containsField(Field field) const U_OVERRIDE; |
| |
| void getParameters(Parameters& output) const U_OVERRIDE; |
| |
| bool semanticallyEquivalent(const Modifier& other) const U_OVERRIDE; |
| |
| /** |
| * TODO: This belongs in SimpleFormatterImpl. The only reason I haven't moved it there yet is because |
| * FormattedStringBuilder is an internal class and SimpleFormatterImpl feels like it should not depend on it. |
| * |
| * <p> |
| * Formats a value that is already stored inside the StringBuilder <code>result</code> between the indices |
| * <code>startIndex</code> and <code>endIndex</code> by inserting characters before the start index and after the |
| * end index. |
| * |
| * <p> |
| * This is well-defined only for patterns with exactly one argument. |
| * |
| * @param result |
| * The StringBuilder containing the value argument. |
| * @param startIndex |
| * The left index of the value within the string builder. |
| * @param endIndex |
| * The right index of the value within the string builder. |
| * @return The number of characters (UTF-16 code points) that were added to the StringBuilder. |
| */ |
| int32_t |
| formatAsPrefixSuffix(FormattedStringBuilder& result, int32_t startIndex, int32_t endIndex, |
| UErrorCode& status) const; |
| |
| /** |
| * TODO: Like above, this belongs with the rest of the SimpleFormatterImpl code. |
| * I put it here so that the SimpleFormatter uses in FormattedStringBuilder are near each other. |
| * |
| * <p> |
| * Applies the compiled two-argument pattern to the FormattedStringBuilder. |
| * |
| * <p> |
| * This method is optimized for the case where the prefix and suffix are often empty, such as |
| * in the range pattern like "{0}-{1}". |
| */ |
| static int32_t |
| formatTwoArgPattern(const SimpleFormatter& compiled, FormattedStringBuilder& result, |
| int32_t index, int32_t* outPrefixLength, int32_t* outSuffixLength, |
| Field field, UErrorCode& status); |
| |
| private: |
| UnicodeString fCompiledPattern; |
| Field fField; |
| bool fStrong = false; |
| int32_t fPrefixLength = 0; |
| int32_t fSuffixOffset = -1; |
| int32_t fSuffixLength = 0; |
| Modifier::Parameters fParameters; |
| }; |
| |
| /** |
| * An implementation of {@link Modifier} that allows for multiple types of fields in the same modifier. Constructed |
| * based on the contents of two {@link FormattedStringBuilder} instances (one for the prefix, one for the suffix). |
| */ |
| class U_I18N_API ConstantMultiFieldModifier : public Modifier, public UMemory { |
| public: |
| ConstantMultiFieldModifier( |
| const FormattedStringBuilder &prefix, |
| const FormattedStringBuilder &suffix, |
| bool overwrite, |
| bool strong, |
| const Modifier::Parameters parameters) |
| : fPrefix(prefix), |
| fSuffix(suffix), |
| fOverwrite(overwrite), |
| fStrong(strong), |
| fParameters(parameters) {} |
| |
| ConstantMultiFieldModifier( |
| const FormattedStringBuilder &prefix, |
| const FormattedStringBuilder &suffix, |
| bool overwrite, |
| bool strong) |
| : fPrefix(prefix), |
| fSuffix(suffix), |
| fOverwrite(overwrite), |
| fStrong(strong) {} |
| |
| int32_t apply(FormattedStringBuilder &output, int32_t leftIndex, int32_t rightIndex, |
| UErrorCode &status) const U_OVERRIDE; |
| |
| int32_t getPrefixLength() const U_OVERRIDE; |
| |
| int32_t getCodePointCount() const U_OVERRIDE; |
| |
| bool isStrong() const U_OVERRIDE; |
| |
| bool containsField(Field field) const U_OVERRIDE; |
| |
| void getParameters(Parameters& output) const U_OVERRIDE; |
| |
| bool semanticallyEquivalent(const Modifier& other) const U_OVERRIDE; |
| |
| protected: |
| // NOTE: In Java, these are stored as array pointers. In C++, the FormattedStringBuilder is stored by |
| // value and is treated internally as immutable. |
| FormattedStringBuilder fPrefix; |
| FormattedStringBuilder fSuffix; |
| bool fOverwrite; |
| bool fStrong; |
| Modifier::Parameters fParameters; |
| }; |
| |
| /** Identical to {@link ConstantMultiFieldModifier}, but supports currency spacing. */ |
| class U_I18N_API CurrencySpacingEnabledModifier : public ConstantMultiFieldModifier { |
| public: |
| /** Safe code path */ |
| CurrencySpacingEnabledModifier( |
| const FormattedStringBuilder &prefix, |
| const FormattedStringBuilder &suffix, |
| bool overwrite, |
| bool strong, |
| const DecimalFormatSymbols &symbols, |
| UErrorCode &status); |
| |
| int32_t apply(FormattedStringBuilder &output, int32_t leftIndex, int32_t rightIndex, |
| UErrorCode &status) const U_OVERRIDE; |
| |
| /** Unsafe code path */ |
| static int32_t |
| applyCurrencySpacing(FormattedStringBuilder &output, int32_t prefixStart, int32_t prefixLen, |
| int32_t suffixStart, int32_t suffixLen, const DecimalFormatSymbols &symbols, |
| UErrorCode &status); |
| |
| private: |
| UnicodeSet fAfterPrefixUnicodeSet; |
| UnicodeString fAfterPrefixInsert; |
| UnicodeSet fBeforeSuffixUnicodeSet; |
| UnicodeString fBeforeSuffixInsert; |
| |
| enum EAffix { |
| PREFIX, SUFFIX |
| }; |
| |
| enum EPosition { |
| IN_CURRENCY, IN_NUMBER |
| }; |
| |
| /** Unsafe code path */ |
| static int32_t applyCurrencySpacingAffix(FormattedStringBuilder &output, int32_t index, EAffix affix, |
| const DecimalFormatSymbols &symbols, UErrorCode &status); |
| |
| static UnicodeSet |
| getUnicodeSet(const DecimalFormatSymbols &symbols, EPosition position, EAffix affix, |
| UErrorCode &status); |
| |
| static UnicodeString |
| getInsertString(const DecimalFormatSymbols &symbols, EAffix affix, UErrorCode &status); |
| }; |
| |
| /** A Modifier that does not do anything. */ |
| class U_I18N_API EmptyModifier : public Modifier, public UMemory { |
| public: |
| explicit EmptyModifier(bool isStrong) : fStrong(isStrong) {} |
| |
| int32_t apply(FormattedStringBuilder &output, int32_t leftIndex, int32_t rightIndex, |
| UErrorCode &status) const U_OVERRIDE { |
| (void)output; |
| (void)leftIndex; |
| (void)rightIndex; |
| (void)status; |
| return 0; |
| } |
| |
| int32_t getPrefixLength() const U_OVERRIDE { |
| return 0; |
| } |
| |
| int32_t getCodePointCount() const U_OVERRIDE { |
| return 0; |
| } |
| |
| bool isStrong() const U_OVERRIDE { |
| return fStrong; |
| } |
| |
| bool containsField(Field field) const U_OVERRIDE { |
| (void)field; |
| return false; |
| } |
| |
| void getParameters(Parameters& output) const U_OVERRIDE { |
| output.obj = nullptr; |
| } |
| |
| bool semanticallyEquivalent(const Modifier& other) const U_OVERRIDE { |
| return other.getCodePointCount() == 0; |
| } |
| |
| private: |
| bool fStrong; |
| }; |
| |
| /** |
| * This implementation of ModifierStore adopts Modifer pointers. |
| */ |
| class U_I18N_API AdoptingModifierStore : public ModifierStore, public UMemory { |
| public: |
| virtual ~AdoptingModifierStore(); |
| |
| static constexpr StandardPlural::Form DEFAULT_STANDARD_PLURAL = StandardPlural::OTHER; |
| |
| AdoptingModifierStore() = default; |
| |
| // No copying! |
| AdoptingModifierStore(const AdoptingModifierStore &other) = delete; |
| |
| /** |
| * Sets the Modifier with the specified signum and plural form. |
| */ |
| void adoptModifier(Signum signum, StandardPlural::Form plural, const Modifier *mod) { |
| U_ASSERT(mods[getModIndex(signum, plural)] == nullptr); |
| mods[getModIndex(signum, plural)] = mod; |
| } |
| |
| /** |
| * Sets the Modifier with the specified signum. |
| * The modifier will apply to all plural forms. |
| */ |
| void adoptModifierWithoutPlural(Signum signum, const Modifier *mod) { |
| U_ASSERT(mods[getModIndex(signum, DEFAULT_STANDARD_PLURAL)] == nullptr); |
| mods[getModIndex(signum, DEFAULT_STANDARD_PLURAL)] = mod; |
| } |
| |
| /** Returns a reference to the modifier; no ownership change. */ |
| const Modifier *getModifier(Signum signum, StandardPlural::Form plural) const U_OVERRIDE { |
| const Modifier* modifier = mods[getModIndex(signum, plural)]; |
| if (modifier == nullptr && plural != DEFAULT_STANDARD_PLURAL) { |
| modifier = mods[getModIndex(signum, DEFAULT_STANDARD_PLURAL)]; |
| } |
| return modifier; |
| } |
| |
| /** Returns a reference to the modifier; no ownership change. */ |
| const Modifier *getModifierWithoutPlural(Signum signum) const { |
| return mods[getModIndex(signum, DEFAULT_STANDARD_PLURAL)]; |
| } |
| |
| private: |
| // NOTE: mods is zero-initialized (to nullptr) |
| const Modifier *mods[4 * StandardPlural::COUNT] = {}; |
| |
| inline static int32_t getModIndex(Signum signum, StandardPlural::Form plural) { |
| U_ASSERT(signum >= 0 && signum < SIGNUM_COUNT); |
| U_ASSERT(plural >= 0 && plural < StandardPlural::COUNT); |
| return static_cast<int32_t>(plural) * SIGNUM_COUNT + signum; |
| } |
| }; |
| |
| } // namespace impl |
| } // namespace number |
| U_NAMESPACE_END |
| |
| |
| #endif //__NUMBER_MODIFIERS_H__ |
| |
| #endif /* #if !UCONFIG_NO_FORMATTING */ |