/* ****************************************************************************** * Copyright (C) 1997-2001, International Business Machines * Corporation and others. All Rights Reserved. ****************************************************************************** * file name: nfsubs.h * encoding: US-ASCII * tab size: 8 (not used) * indentation:4 * * Modification history * Date Name Comments * 10/11/2001 Doug Ported from ICU4J */ #ifndef NFSUBS_H #define NFSUBS_H #include "unicode/utypes.h" #include "unicode/uobject.h" #include "nfrule.h" #if U_HAVE_RBNF #include "unicode/utypes.h" #include "unicode/decimfmt.h" #include "nfrs.h" #include U_NAMESPACE_BEGIN class NFSubstitution : public UObject { int32_t pos; const NFRuleSet* ruleSet; const DecimalFormat* numberFormat; protected: NFSubstitution(int32_t pos, const NFRuleSet* ruleSet, const RuleBasedNumberFormat* rbnf, const UnicodeString& description, UErrorCode& status); /** * Get the Ruleset of the object. * @return the Ruleset of the object. */ const NFRuleSet* getRuleSet() const { return ruleSet; } /** * get the NumberFormat of this object. * @return the numberformat of this object. */ const DecimalFormat* getNumberFormat() const { return numberFormat; } public: static NFSubstitution* makeSubstitution(int32_t pos, const NFRule* rule, const NFRule* predecessor, const NFRuleSet* ruleSet, const RuleBasedNumberFormat* rbnf, const UnicodeString& description, UErrorCode& status); /** * Destructor. */ virtual ~NFSubstitution(); /** * Return true if the given Format objects are semantically equal. * Objects of different subclasses are considered unequal. * @param rhs the object to be compared with. * @return true if the given Format objects are semantically equal. */ virtual UBool operator==(const NFSubstitution& rhs) const; /** * Return true if the given Format objects are semantically unequal. * Objects of different subclasses are considered unequal. * @param rhs the object to be compared with. * @return true if the given Format objects are semantically unequal. */ UBool operator!=(const NFSubstitution& rhs) const { return !operator==(rhs); } /** * Sets the substitution's divisor. Used by NFRule.setBaseValue(). * A no-op for all substitutions except multiplier and modulus * substitutions. * @param radix The radix of the divisor * @param exponent The exponent of the divisor */ virtual void setDivisor(int32_t radix, int32_t exponent); /** * Replaces result with the string describing the substitution. * @param result Output param which will receive the string. */ virtual void toString(UnicodeString& result) const; //----------------------------------------------------------------------- // formatting //----------------------------------------------------------------------- /** * Performs a mathematical operation on the number, formats it using * either ruleSet or decimalFormat, and inserts the result into * toInsertInto. * @param number The number being formatted. * @param toInsertInto The string we insert the result into * @param pos The position in toInsertInto where the owning rule's * rule text begins (this value is added to this substitution's * position to determine exactly where to insert the new text) */ virtual void doSubstitution(int64_t number, UnicodeString& toInsertInto, int32_t pos) const; /** * Performs a mathematical operation on the number, formats it using * either ruleSet or decimalFormat, and inserts the result into * toInsertInto. * @param number The number being formatted. * @param toInsertInto The string we insert the result into * @param pos The position in toInsertInto where the owning rule's * rule text begins (this value is added to this substitution's * position to determine exactly where to insert the new text) */ virtual void doSubstitution(double number, UnicodeString& toInsertInto, int32_t pos) const; protected: /** * Subclasses override this function to perform some kind of * mathematical operation on the number. The result of this operation * is formatted using the rule set or DecimalFormat that this * substitution refers to, and the result is inserted into the result * string. * @param The number being formatted * @return The result of performing the opreration on the number */ virtual int64_t transformNumber(int64_t number) const = 0; /** * Subclasses override this function to perform some kind of * mathematical operation on the number. The result of this operation * is formatted using the rule set or DecimalFormat that this * substitution refers to, and the result is inserted into the result * string. * @param The number being formatted * @return The result of performing the opreration on the number */ virtual double transformNumber(double number) const = 0; public: //----------------------------------------------------------------------- // parsing //----------------------------------------------------------------------- /** * Parses a string using the rule set or DecimalFormat belonging * to this substitution. If there's a match, a mathematical * operation (the inverse of the one used in formatting) is * performed on the result of the parse and the value passed in * and returned as the result. The parse position is updated to * point to the first unmatched character in the string. * @param text The string to parse * @param parsePosition On entry, ignored, but assumed to be 0. * On exit, this is updated to point to the first unmatched * character (or 0 if the substitution didn't match) * @param baseValue A partial parse result that should be * combined with the result of this parse * @param upperBound When searching the rule set for a rule * matching the string passed in, only rules with base values * lower than this are considered * @param lenientParse If true and matching against rules fails, * the substitution will also try matching the text against * numerals using a default-costructed NumberFormat. If false, * no extra work is done. (This value is false whenever the * formatter isn't in lenient-parse mode, but is also false * under some conditions even when the formatter _is_ in * lenient-parse mode.) * @return If there's a match, this is the result of composing * baseValue with whatever was returned from matching the * characters. This will be either a Long or a Double. If there's * no match this is new Long(0) (not null), and parsePosition * is left unchanged. */ virtual UBool doParse(const UnicodeString& text, ParsePosition& parsePosition, double baseValue, double upperBound, UBool lenientParse, Formattable& result) const; /** * Derives a new value from the two values passed in. The two values * are typically either the base values of two rules (the one containing * the substitution and the one matching the substitution) or partial * parse results derived in some other way. The operation is generally * the inverse of the operation performed by transformNumber(). * @param newRuleValue The value produced by matching this substitution * @param oldRuleValue The value that was passed to the substitution * by the rule that owns it * @return A third value derived from the other two, representing a * partial parse result */ virtual double composeRuleValue(double newRuleValue, double oldRuleValue) const = 0; /** * Calculates an upper bound when searching for a rule that matches * this substitution. Rules with base values greater than or equal * to upperBound are not considered. * @param oldUpperBound The current upper-bound setting. The new * upper bound can't be any higher. * @return the upper bound when searching for a rule that matches * this substitution. */ virtual double calcUpperBound(double oldUpperBound) const = 0; //----------------------------------------------------------------------- // simple accessors //----------------------------------------------------------------------- /** * Returns the substitution's position in the rule that owns it. * @return The substitution's position in the rule that owns it. */ int32_t getPos() const { return pos; } /** * Returns the character used in the textual representation of * substitutions of this type. Used by toString(). * @return This substitution's token character. */ virtual UChar tokenChar() const = 0; /** * Returns true if this is a null substitution. (We didn't do this * with instanceof partially because it causes source files to * proliferate and partially because we have to port this to C++.) * @return true if this object is an instance of NullSubstitution */ virtual UBool isNullSubstitution() const; /** * Returns true if this is a modulus substitution. (We didn't do this * with instanceof partially because it causes source files to * proliferate and partially because we have to port this to C++.) * @return true if this object is an instance of ModulusSubstitution */ virtual UBool isModulusSubstitution() const; private: static const char fgClassID; public: static UClassID getStaticClassID(void) { return (UClassID)&fgClassID; } virtual UClassID getDynamicClassID(void) const; }; class SameValueSubstitution : public NFSubstitution { public: SameValueSubstitution(int32_t pos, const NFRuleSet* ruleset, const RuleBasedNumberFormat* formatter, const UnicodeString& description, UErrorCode& status); int64_t transformNumber(int64_t number) const { return number; } double transformNumber(double number) const { return number; } double composeRuleValue(double newRuleValue, double /*oldRuleValue*/) const { return newRuleValue; } double calcUpperBound(double oldUpperBound) const { return oldUpperBound; } UChar tokenChar() const { return (UChar)0x003d; } // '=' private: static const char fgClassID; public: static UClassID getStaticClassID(void) { return (UClassID)&fgClassID; } virtual UClassID getDynamicClassID(void) const; }; class MultiplierSubstitution : public NFSubstitution { double divisor; int64_t ldivisor; public: MultiplierSubstitution(int32_t _pos, double _divisor, const NFRuleSet* _ruleSet, const RuleBasedNumberFormat* formatter, const UnicodeString& description, UErrorCode& status) : NFSubstitution(_pos, _ruleSet, formatter, description, status), divisor(_divisor) { ldivisor = util64_fromDouble(divisor); } void setDivisor(int32_t radix, int32_t exponent) { divisor = uprv_pow(radix, exponent); ldivisor = util64_fromDouble(divisor); } UBool operator==(const NFSubstitution& rhs) const; int64_t transformNumber(int64_t number) const { return number / ldivisor; } double transformNumber(double number) const { return uprv_floor(number / divisor); } double composeRuleValue(double newRuleValue, double /*oldRuleValue*/) const { return newRuleValue * divisor; } double calcUpperBound(double /*oldUpperBound*/) const { return divisor; } UChar tokenChar() const { return (UChar)0x003c; } // '<' private: static const char fgClassID; public: static UClassID getStaticClassID(void) { return (UClassID)&fgClassID; } virtual UClassID getDynamicClassID(void) const; }; class ModulusSubstitution : public NFSubstitution { double divisor; int64_t ldivisor; const NFRule* ruleToUse; public: ModulusSubstitution(int32_t pos, double _divisor, const NFRule* rulePredecessor, const NFRuleSet* ruleSet, const RuleBasedNumberFormat* formatter, const UnicodeString& description, UErrorCode& status); void setDivisor(int32_t radix, int32_t exponent) { divisor = uprv_pow(radix, exponent); ldivisor = util64_fromDouble(divisor); } UBool operator==(const NFSubstitution& rhs) const; void doSubstitution(int64_t number, UnicodeString& toInsertInto, int32_t pos) const; void doSubstitution(double number, UnicodeString& toInsertInto, int32_t pos) const; int64_t transformNumber(int64_t number) const { return number % ldivisor; } double transformNumber(double number) const { return uprv_fmod(number, divisor); } UBool doParse(const UnicodeString& text, ParsePosition& parsePosition, double baseValue, double upperBound, UBool lenientParse, Formattable& result) const; double composeRuleValue(double newRuleValue, double oldRuleValue) const { return oldRuleValue - uprv_fmod(oldRuleValue, divisor) + newRuleValue; } double calcUpperBound(double /*oldUpperBound*/) const { return divisor; } UBool isModulusSubstitution() const { return TRUE; } UChar tokenChar() const { return (UChar)0x003e; } // '>' private: static const char fgClassID; public: static UClassID getStaticClassID(void) { return (UClassID)&fgClassID; } virtual UClassID getDynamicClassID(void) const; }; class IntegralPartSubstitution : public NFSubstitution { public: IntegralPartSubstitution(int32_t _pos, const NFRuleSet* _ruleSet, const RuleBasedNumberFormat* formatter, const UnicodeString& description, UErrorCode& status) : NFSubstitution(_pos, _ruleSet, formatter, description, status) {} int64_t transformNumber(int64_t number) const { return number; } double transformNumber(double number) const { return uprv_floor(number); } double composeRuleValue(double newRuleValue, double oldRuleValue) const { return newRuleValue + oldRuleValue; } double calcUpperBound(double /*oldUpperBound*/) const { return DBL_MAX; } UChar tokenChar() const { return (UChar)0x003c; } // '<' private: static const char fgClassID; public: static UClassID getStaticClassID(void) { return (UClassID)&fgClassID; } virtual UClassID getDynamicClassID(void) const; }; class FractionalPartSubstitution : public NFSubstitution { UBool byDigits; UBool useSpaces; enum { kMaxDecimalDigits = 8 }; public: FractionalPartSubstitution(int32_t pos, const NFRuleSet* ruleSet, const RuleBasedNumberFormat* formatter, const UnicodeString& description, UErrorCode& status); UBool operator==(const NFSubstitution& rhs) const; void doSubstitution(double number, UnicodeString& toInsertInto, int32_t pos) const; void doSubstitution(int64_t /*number*/, UnicodeString& /*toInsertInto*/, int32_t /*_pos*/) const {} int64_t transformNumber(int64_t /*number*/) const { return 0; } double transformNumber(double number) const { return number - uprv_floor(number); } UBool doParse(const UnicodeString& text, ParsePosition& parsePosition, double baseValue, double upperBound, UBool lenientParse, Formattable& result) const; double composeRuleValue(double newRuleValue, double oldRuleValue) const { return newRuleValue + oldRuleValue; } double calcUpperBound(double /*oldUpperBound*/) const { return 0.0; } UChar tokenChar() const { return (UChar)0x003e; } // '>' private: static const char fgClassID; public: static UClassID getStaticClassID(void) { return (UClassID)&fgClassID; } virtual UClassID getDynamicClassID(void) const; }; class AbsoluteValueSubstitution : public NFSubstitution { public: AbsoluteValueSubstitution(int32_t _pos, const NFRuleSet* _ruleSet, const RuleBasedNumberFormat* formatter, const UnicodeString& description, UErrorCode& status) : NFSubstitution(_pos, _ruleSet, formatter, description, status) {} int64_t transformNumber(int64_t number) const { return number >= 0 ? number : -number; } double transformNumber(double number) const { return uprv_fabs(number); } double composeRuleValue(double newRuleValue, double /*oldRuleValue*/) const { return -newRuleValue; } double calcUpperBound(double /*oldUpperBound*/) const { return DBL_MAX; } UChar tokenChar() const { return (UChar)0x003e; } // '>' private: static const char fgClassID; public: static UClassID getStaticClassID(void) { return (UClassID)&fgClassID; } virtual UClassID getDynamicClassID(void) const; }; class NumeratorSubstitution : public NFSubstitution { double denominator; int64_t ldenominator; public: NumeratorSubstitution(int32_t _pos, double _denominator, const NFRuleSet* _ruleSet, const RuleBasedNumberFormat* formatter, const UnicodeString& description, UErrorCode& status) : NFSubstitution(_pos, _ruleSet, formatter, description, status), denominator(_denominator) { ldenominator = util64_fromDouble(denominator); } UBool operator==(const NFSubstitution& rhs) const; int64_t transformNumber(int64_t number) const { return number * ldenominator; } double transformNumber(double number) const { return uprv_round(number * denominator); } UBool doParse(const UnicodeString& text, ParsePosition& parsePosition, double baseValue, double upperBound, UBool /*lenientParse*/, Formattable& result) const { // we don't have to do anything special to do the parsing here, // but we have to turn lenient parsing off-- if we leave it on, // it SERIOUSLY messes up the algorithm return NFSubstitution::doParse(text, parsePosition, baseValue, upperBound, FALSE, result); } double composeRuleValue(double newRuleValue, double oldRuleValue) const { return newRuleValue / oldRuleValue; } double calcUpperBound(double /*oldUpperBound*/) const { return denominator; } UChar tokenChar() const { return (UChar)0x003c; } // '<' private: static const char fgClassID; public: static UClassID getStaticClassID(void) { return (UClassID)&fgClassID; } virtual UClassID getDynamicClassID(void) const; }; class NullSubstitution : public NFSubstitution { public: NullSubstitution(int32_t _pos, const NFRuleSet* _ruleSet, const RuleBasedNumberFormat* formatter, const UnicodeString& description, UErrorCode& status) : NFSubstitution(_pos, _ruleSet, formatter, description, status) {} void toString(UnicodeString& /*result*/) const {} void doSubstitution(double /*number*/, UnicodeString& /*toInsertInto*/, int32_t /*_pos*/) const {} void doSubstitution(int64_t /*number*/, UnicodeString& /*toInsertInto*/, int32_t /*_pos*/) const {} int64_t transformNumber(int64_t /*number*/) const { return 0; } double transformNumber(double /*number*/) const { return 0; } UBool doParse(const UnicodeString& /*text*/, ParsePosition& /*parsePosition*/, double baseValue, double /*upperBound*/, UBool /*lenientParse*/, Formattable& result) const { result.setDouble(baseValue); return TRUE; } double composeRuleValue(double /*newRuleValue*/, double /*oldRuleValue*/) const { return 0.0; } // never called double calcUpperBound(double /*oldUpperBound*/) const { return 0; } // never called UBool isNullSubstitution() const { return TRUE; } UChar tokenChar() const { return (UChar)0x0020; } // ' ' never called private: static const char fgClassID; public: static UClassID getStaticClassID(void) { return (UClassID)&fgClassID; } virtual UClassID getDynamicClassID(void) const; }; U_NAMESPACE_END /* U_HAVE_RBNF */ #endif // NFSUBS_H #endif