intl/icu/source/i18n/nfsubs.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /*
     2 ******************************************************************************
     3 *   Copyright (C) 1997-2012, International Business Machines
     4 *   Corporation and others.  All Rights Reserved.
     5 ******************************************************************************
     6 *   file name:  nfsubs.cpp
     7 *   encoding:   US-ASCII
     8 *   tab size:   8 (not used)
     9 *   indentation:4
    10 *
    11 * Modification history
    12 * Date        Name      Comments
    13 * 10/11/2001  Doug      Ported from ICU4J
    14 */
    16 #include <stdio.h>
    17 #include "utypeinfo.h"  // for 'typeid' to work
    19 #include "nfsubs.h"
    20 #include "digitlst.h"
    22 #if U_HAVE_RBNF
    24 static const UChar gLessThan = 0x003c;
    25 static const UChar gEquals = 0x003d;
    26 static const UChar gGreaterThan = 0x003e;
    27 static const UChar gPercent = 0x0025;
    28 static const UChar gPound = 0x0023;
    29 static const UChar gZero = 0x0030;
    30 static const UChar gSpace = 0x0020;
    32 static const UChar gEqualsEquals[] =
    33 {
    34     0x3D, 0x3D, 0
    35 }; /* "==" */
    36 static const UChar gGreaterGreaterGreaterThan[] =
    37 {
    38     0x3E, 0x3E, 0x3E, 0
    39 }; /* ">>>" */
    40 static const UChar gGreaterGreaterThan[] =
    41 {
    42     0x3E, 0x3E, 0
    43 }; /* ">>" */
    45 U_NAMESPACE_BEGIN
    47 class SameValueSubstitution : public NFSubstitution {
    48 public:
    49     SameValueSubstitution(int32_t pos,
    50         const NFRuleSet* ruleset,
    51         const RuleBasedNumberFormat* formatter,
    52         const UnicodeString& description,
    53         UErrorCode& status);
    54     virtual ~SameValueSubstitution();
    56     virtual int64_t transformNumber(int64_t number) const { return number; }
    57     virtual double transformNumber(double number) const { return number; }
    58     virtual double composeRuleValue(double newRuleValue, double /*oldRuleValue*/) const { return newRuleValue; }
    59     virtual double calcUpperBound(double oldUpperBound) const { return oldUpperBound; }
    60     virtual UChar tokenChar() const { return (UChar)0x003d; } // '='
    62 public:
    63     static UClassID getStaticClassID(void);
    64     virtual UClassID getDynamicClassID(void) const;
    65 };
    67 SameValueSubstitution::~SameValueSubstitution() {}
    69 class MultiplierSubstitution : public NFSubstitution {
    70     double divisor;
    71     int64_t ldivisor;
    73 public:
    74     MultiplierSubstitution(int32_t _pos,
    75         double _divisor,
    76         const NFRuleSet* _ruleSet,
    77         const RuleBasedNumberFormat* formatter,
    78         const UnicodeString& description,
    79         UErrorCode& status)
    80         : NFSubstitution(_pos, _ruleSet, formatter, description, status), divisor(_divisor)
    81     {
    82         ldivisor = util64_fromDouble(divisor);
    83         if (divisor == 0) {
    84             status = U_PARSE_ERROR;
    85         }
    86     }
    87     virtual ~MultiplierSubstitution();
    89     virtual void setDivisor(int32_t radix, int32_t exponent, UErrorCode& status) { 
    90         divisor = uprv_pow(radix, exponent);
    91         ldivisor = util64_fromDouble(divisor);
    93         if(divisor == 0) {
    94             status = U_PARSE_ERROR;
    95         }
    96     }
    98     virtual UBool operator==(const NFSubstitution& rhs) const;
   100     virtual int64_t transformNumber(int64_t number) const {
   101         return number / ldivisor;
   102     }
   104     virtual double transformNumber(double number) const {
   105         if (getRuleSet()) {
   106             return uprv_floor(number / divisor);
   107         } else {
   108             return number/divisor;
   109         }
   110     }
   112     virtual double composeRuleValue(double newRuleValue, double /*oldRuleValue*/) const {
   113         return newRuleValue * divisor;
   114     }
   116     virtual double calcUpperBound(double /*oldUpperBound*/) const { return divisor; }
   118     virtual UChar tokenChar() const { return (UChar)0x003c; } // '<'
   120 public:
   121     static UClassID getStaticClassID(void);
   122     virtual UClassID getDynamicClassID(void) const;
   123 };
   125 MultiplierSubstitution::~MultiplierSubstitution() {}
   127 class ModulusSubstitution : public NFSubstitution {
   128     double divisor;
   129     int64_t  ldivisor;
   130     const NFRule* ruleToUse;
   131 public:
   132     ModulusSubstitution(int32_t pos,
   133         double _divisor,
   134         const NFRule* rulePredecessor,
   135         const NFRuleSet* ruleSet,
   136         const RuleBasedNumberFormat* formatter,
   137         const UnicodeString& description,
   138         UErrorCode& status);
   139     virtual ~ModulusSubstitution();
   141     virtual void setDivisor(int32_t radix, int32_t exponent, UErrorCode& status) { 
   142         divisor = uprv_pow(radix, exponent);
   143         ldivisor = util64_fromDouble(divisor);
   145         if (divisor == 0) {
   146             status = U_PARSE_ERROR;
   147         }
   148     }
   150     virtual UBool operator==(const NFSubstitution& rhs) const;
   152     virtual void doSubstitution(int64_t number, UnicodeString& toInsertInto, int32_t pos) const;
   153     virtual void doSubstitution(double number, UnicodeString& toInsertInto, int32_t pos) const;
   155     virtual int64_t transformNumber(int64_t number) const { return number % ldivisor; }
   156     virtual double transformNumber(double number) const { return uprv_fmod(number, divisor); }
   158     virtual UBool doParse(const UnicodeString& text, 
   159         ParsePosition& parsePosition,
   160         double baseValue,
   161         double upperBound,
   162         UBool lenientParse,
   163         Formattable& result) const;
   165     virtual double composeRuleValue(double newRuleValue, double oldRuleValue) const {
   166         return oldRuleValue - uprv_fmod(oldRuleValue, divisor) + newRuleValue;
   167     }
   169     virtual double calcUpperBound(double /*oldUpperBound*/) const { return divisor; }
   171     virtual UBool isModulusSubstitution() const { return TRUE; }
   173     virtual UChar tokenChar() const { return (UChar)0x003e; } // '>'
   175 	virtual void toString(UnicodeString& result) const;
   177 public:
   178     static UClassID getStaticClassID(void);
   179     virtual UClassID getDynamicClassID(void) const;
   180 };
   182 ModulusSubstitution::~ModulusSubstitution() {}
   184 class IntegralPartSubstitution : public NFSubstitution {
   185 public:
   186     IntegralPartSubstitution(int32_t _pos,
   187         const NFRuleSet* _ruleSet,
   188         const RuleBasedNumberFormat* formatter,
   189         const UnicodeString& description,
   190         UErrorCode& status)
   191         : NFSubstitution(_pos, _ruleSet, formatter, description, status) {}
   192     virtual ~IntegralPartSubstitution();
   194     virtual int64_t transformNumber(int64_t number) const { return number; }
   195     virtual double transformNumber(double number) const { return uprv_floor(number); }
   196     virtual double composeRuleValue(double newRuleValue, double oldRuleValue) const { return newRuleValue + oldRuleValue; }
   197     virtual double calcUpperBound(double /*oldUpperBound*/) const { return DBL_MAX; }
   198     virtual UChar tokenChar() const { return (UChar)0x003c; } // '<'
   200 public:
   201     static UClassID getStaticClassID(void);
   202     virtual UClassID getDynamicClassID(void) const;
   203 };
   205 IntegralPartSubstitution::~IntegralPartSubstitution() {}
   207 class FractionalPartSubstitution : public NFSubstitution {
   208     UBool byDigits;
   209     UBool useSpaces;
   210     enum { kMaxDecimalDigits = 8 };
   211 public:
   212     FractionalPartSubstitution(int32_t pos,
   213         const NFRuleSet* ruleSet,
   214         const RuleBasedNumberFormat* formatter,
   215         const UnicodeString& description,
   216         UErrorCode& status);
   217     virtual ~FractionalPartSubstitution();
   219     virtual UBool operator==(const NFSubstitution& rhs) const;
   221     virtual void doSubstitution(double number, UnicodeString& toInsertInto, int32_t pos) const;
   222     virtual void doSubstitution(int64_t /*number*/, UnicodeString& /*toInsertInto*/, int32_t /*_pos*/) const {}
   223     virtual int64_t transformNumber(int64_t /*number*/) const { return 0; }
   224     virtual double transformNumber(double number) const { return number - uprv_floor(number); }
   226     virtual UBool doParse(const UnicodeString& text,
   227         ParsePosition& parsePosition,
   228         double baseValue,
   229         double upperBound,
   230         UBool lenientParse,
   231         Formattable& result) const;
   233     virtual double composeRuleValue(double newRuleValue, double oldRuleValue) const { return newRuleValue + oldRuleValue; }
   234     virtual double calcUpperBound(double /*oldUpperBound*/) const { return 0.0; }
   235     virtual UChar tokenChar() const { return (UChar)0x003e; } // '>'
   237 public:
   238     static UClassID getStaticClassID(void);
   239     virtual UClassID getDynamicClassID(void) const;
   240 };
   242 FractionalPartSubstitution::~FractionalPartSubstitution() {}
   244 class AbsoluteValueSubstitution : public NFSubstitution {
   245 public:
   246     AbsoluteValueSubstitution(int32_t _pos,
   247         const NFRuleSet* _ruleSet,
   248         const RuleBasedNumberFormat* formatter,
   249         const UnicodeString& description,
   250         UErrorCode& status)
   251         : NFSubstitution(_pos, _ruleSet, formatter, description, status) {}
   252     virtual ~AbsoluteValueSubstitution();
   254     virtual int64_t transformNumber(int64_t number) const { return number >= 0 ? number : -number; }
   255     virtual double transformNumber(double number) const { return uprv_fabs(number); }
   256     virtual double composeRuleValue(double newRuleValue, double /*oldRuleValue*/) const { return -newRuleValue; }
   257     virtual double calcUpperBound(double /*oldUpperBound*/) const { return DBL_MAX; }
   258     virtual UChar tokenChar() const { return (UChar)0x003e; } // '>'
   260 public:
   261     static UClassID getStaticClassID(void);
   262     virtual UClassID getDynamicClassID(void) const;
   263 };
   265 AbsoluteValueSubstitution::~AbsoluteValueSubstitution() {}
   267 class NumeratorSubstitution : public NFSubstitution {
   268     double denominator;
   269     int64_t ldenominator;
   270     UBool withZeros;
   271 public:
   272     static inline UnicodeString fixdesc(const UnicodeString& desc) {
   273         if (desc.endsWith(LTLT, 2)) {
   274             UnicodeString result(desc, 0, desc.length()-1);
   275             return result;
   276         }
   277         return desc;
   278     }
   279     NumeratorSubstitution(int32_t _pos,
   280         double _denominator,
   281         const NFRuleSet* _ruleSet,
   282         const RuleBasedNumberFormat* formatter,
   283         const UnicodeString& description,
   284         UErrorCode& status)
   285         : NFSubstitution(_pos, _ruleSet, formatter, fixdesc(description), status), denominator(_denominator) 
   286     {
   287         ldenominator = util64_fromDouble(denominator);
   288         withZeros = description.endsWith(LTLT, 2);
   289     }
   290     virtual ~NumeratorSubstitution();
   292     virtual UBool operator==(const NFSubstitution& rhs) const;
   294     virtual int64_t transformNumber(int64_t number) const { return number * ldenominator; }
   295     virtual double transformNumber(double number) const { return uprv_round(number * denominator); }
   297     virtual void doSubstitution(int64_t /*number*/, UnicodeString& /*toInsertInto*/, int32_t /*_pos*/) const {}
   298     virtual void doSubstitution(double number, UnicodeString& toInsertInto, int32_t pos) const;
   299     virtual UBool doParse(const UnicodeString& text, 
   300         ParsePosition& parsePosition,
   301         double baseValue,
   302         double upperBound,
   303         UBool /*lenientParse*/,
   304         Formattable& result) const;
   306     virtual double composeRuleValue(double newRuleValue, double oldRuleValue) const { return newRuleValue / oldRuleValue; }
   307     virtual double calcUpperBound(double /*oldUpperBound*/) const { return denominator; }
   308     virtual UChar tokenChar() const { return (UChar)0x003c; } // '<'
   309 private:
   310     static const UChar LTLT[2];
   312 public:
   313     static UClassID getStaticClassID(void);
   314     virtual UClassID getDynamicClassID(void) const;
   315 };
   317 NumeratorSubstitution::~NumeratorSubstitution() {}
   319 class NullSubstitution : public NFSubstitution {
   320 public:
   321     NullSubstitution(int32_t _pos,
   322         const NFRuleSet* _ruleSet,
   323         const RuleBasedNumberFormat* formatter,
   324         const UnicodeString& description,
   325         UErrorCode& status)
   326         : NFSubstitution(_pos, _ruleSet, formatter, description, status) {}
   327     virtual ~NullSubstitution();
   329     virtual void toString(UnicodeString& /*result*/) const {}
   330     virtual void doSubstitution(double /*number*/, UnicodeString& /*toInsertInto*/, int32_t /*_pos*/) const {}
   331     virtual void doSubstitution(int64_t /*number*/, UnicodeString& /*toInsertInto*/, int32_t /*_pos*/) const {}
   332     virtual int64_t transformNumber(int64_t /*number*/) const { return 0; }
   333     virtual double transformNumber(double /*number*/) const { return 0; }
   334     virtual UBool doParse(const UnicodeString& /*text*/,
   335         ParsePosition& /*parsePosition*/, 
   336         double baseValue,
   337         double /*upperBound*/,
   338         UBool /*lenientParse*/,
   339         Formattable& result) const
   340     { result.setDouble(baseValue); return TRUE; }
   341     virtual double composeRuleValue(double /*newRuleValue*/, double /*oldRuleValue*/) const { return 0.0; } // never called
   342     virtual double calcUpperBound(double /*oldUpperBound*/) const { return 0; } // never called
   343     virtual UBool isNullSubstitution() const { return TRUE; }
   344     virtual UChar tokenChar() const { return (UChar)0x0020; } // ' ' never called
   346 public:
   347     static UClassID getStaticClassID(void);
   348     virtual UClassID getDynamicClassID(void) const;
   349 };
   351 NullSubstitution::~NullSubstitution() {}
   353 NFSubstitution*
   354 NFSubstitution::makeSubstitution(int32_t pos,
   355                                  const NFRule* rule,
   356                                  const NFRule* predecessor,
   357                                  const NFRuleSet* ruleSet,
   358                                  const RuleBasedNumberFormat* formatter,
   359                                  const UnicodeString& description,
   360                                  UErrorCode& status)
   361 {
   362     // if the description is empty, return a NullSubstitution
   363     if (description.length() == 0) {
   364         return new NullSubstitution(pos, ruleSet, formatter, description, status);
   365     }
   367     switch (description.charAt(0)) {
   368         // if the description begins with '<'...
   369     case gLessThan:
   370         // throw an exception if the rule is a negative number
   371         // rule
   372         if (rule->getBaseValue() == NFRule::kNegativeNumberRule) {
   373             // throw new IllegalArgumentException("<< not allowed in negative-number rule");
   374             status = U_PARSE_ERROR;
   375             return NULL;
   376         }
   378         // if the rule is a fraction rule, return an
   379         // IntegralPartSubstitution
   380         else if (rule->getBaseValue() == NFRule::kImproperFractionRule
   381             || rule->getBaseValue() == NFRule::kProperFractionRule
   382             || rule->getBaseValue() == NFRule::kMasterRule) {
   383             return new IntegralPartSubstitution(pos, ruleSet, formatter, description, status);
   384         }
   386         // if the rule set containing the rule is a fraction
   387         // rule set, return a NumeratorSubstitution
   388         else if (ruleSet->isFractionRuleSet()) {
   389             return new NumeratorSubstitution(pos, (double)rule->getBaseValue(),
   390                 formatter->getDefaultRuleSet(), formatter, description, status);
   391         }
   393         // otherwise, return a MultiplierSubstitution
   394         else {
   395             return new MultiplierSubstitution(pos, rule->getDivisor(), ruleSet,
   396                 formatter, description, status);
   397         }
   399         // if the description begins with '>'...
   400     case gGreaterThan:
   401         // if the rule is a negative-number rule, return
   402         // an AbsoluteValueSubstitution
   403         if (rule->getBaseValue() == NFRule::kNegativeNumberRule) {
   404             return new AbsoluteValueSubstitution(pos, ruleSet, formatter, description, status);
   405         }
   407         // if the rule is a fraction rule, return a
   408         // FractionalPartSubstitution
   409         else if (rule->getBaseValue() == NFRule::kImproperFractionRule
   410             || rule->getBaseValue() == NFRule::kProperFractionRule
   411             || rule->getBaseValue() == NFRule::kMasterRule) {
   412             return new FractionalPartSubstitution(pos, ruleSet, formatter, description, status);
   413         }
   415         // if the rule set owning the rule is a fraction rule set,
   416         // throw an exception
   417         else if (ruleSet->isFractionRuleSet()) {
   418             // throw new IllegalArgumentException(">> not allowed in fraction rule set");
   419             status = U_PARSE_ERROR;
   420             return NULL;
   421         }
   423         // otherwise, return a ModulusSubstitution
   424         else {
   425             return new ModulusSubstitution(pos, rule->getDivisor(), predecessor,
   426                 ruleSet, formatter, description, status);
   427         }
   429         // if the description begins with '=', always return a
   430         // SameValueSubstitution
   431     case gEquals:
   432         return new SameValueSubstitution(pos, ruleSet, formatter, description, status);
   434         // and if it's anything else, throw an exception
   435     default:
   436         // throw new IllegalArgumentException("Illegal substitution character");
   437         status = U_PARSE_ERROR;
   438     }
   439     return NULL;
   440 }
   442 NFSubstitution::NFSubstitution(int32_t _pos,
   443                                const NFRuleSet* _ruleSet,
   444                                const RuleBasedNumberFormat* formatter,
   445                                const UnicodeString& description,
   446                                UErrorCode& status)
   447                                : pos(_pos), ruleSet(NULL), numberFormat(NULL)
   448 {
   449     // the description should begin and end with the same character.
   450     // If it doesn't that's a syntax error.  Otherwise,
   451     // makeSubstitution() was the only thing that needed to know
   452     // about these characters, so strip them off
   453     UnicodeString workingDescription(description);
   454     if (description.length() >= 2
   455         && description.charAt(0) == description.charAt(description.length() - 1))
   456     {
   457         workingDescription.remove(description.length() - 1, 1);
   458         workingDescription.remove(0, 1);
   459     }
   460     else if (description.length() != 0) {
   461         // throw new IllegalArgumentException("Illegal substitution syntax");
   462         status = U_PARSE_ERROR;
   463         return;
   464     }
   466     // if the description was just two paired token characters
   467     // (i.e., "<<" or ">>"), it uses the rule set it belongs to to
   468     // format its result
   469     if (workingDescription.length() == 0) {
   470         this->ruleSet = _ruleSet;
   471     }
   472     // if the description contains a rule set name, that's the rule
   473     // set we use to format the result: get a reference to the
   474     // names rule set
   475     else if (workingDescription.charAt(0) == gPercent) {
   476         this->ruleSet = formatter->findRuleSet(workingDescription, status);
   477     }
   478     // if the description begins with 0 or #, treat it as a
   479     // DecimalFormat pattern, and initialize a DecimalFormat with
   480     // that pattern (then set it to use the DecimalFormatSymbols
   481     // belonging to our formatter)
   482     else if (workingDescription.charAt(0) == gPound || workingDescription.charAt(0) ==gZero) {
   483         DecimalFormatSymbols* sym = formatter->getDecimalFormatSymbols();
   484         if (!sym) {
   485             status = U_MISSING_RESOURCE_ERROR;
   486             return;
   487         }
   488         this->numberFormat = new DecimalFormat(workingDescription, *sym, status);
   489         /* test for NULL */
   490         if (this->numberFormat == 0) {
   491             status = U_MEMORY_ALLOCATION_ERROR;
   492             return;
   493         }
   494         if (U_FAILURE(status)) {
   495             delete (DecimalFormat*)this->numberFormat;
   496             this->numberFormat = NULL;
   497             return;
   498         }
   499         // this->numberFormat->setDecimalFormatSymbols(formatter->getDecimalFormatSymbols());
   500     }
   501     // if the description is ">>>", this substitution bypasses the
   502     // usual rule-search process and always uses the rule that precedes
   503     // it in its own rule set's rule list (this is used for place-value
   504     // notations: formats where you want to see a particular part of
   505     // a number even when it's 0)
   506     else if (workingDescription.charAt(0) == gGreaterThan) {
   507         // this causes problems when >>> is used in a frationalPartSubstitution
   508         // this->ruleSet = NULL;
   509         this->ruleSet = _ruleSet;
   510         this->numberFormat = NULL;
   511     }
   512     // and of the description is none of these things, it's a syntax error
   513     else {
   514         // throw new IllegalArgumentException("Illegal substitution syntax");
   515         status = U_PARSE_ERROR;
   516     }
   517 }
   519 NFSubstitution::~NFSubstitution()
   520 {
   521   // cast away const
   522   delete (NumberFormat*)numberFormat; numberFormat = NULL;
   523 }
   525 /**
   526  * Set's the substitution's divisor.  Used by NFRule.setBaseValue().
   527  * A no-op for all substitutions except multiplier and modulus
   528  * substitutions.
   529  * @param radix The radix of the divisor
   530  * @param exponent The exponent of the divisor
   531  */
   532 void
   533 NFSubstitution::setDivisor(int32_t /*radix*/, int32_t /*exponent*/, UErrorCode& /*status*/) {
   534   // a no-op for all substitutions except multiplier and modulus substitutions
   535 }
   538 //-----------------------------------------------------------------------
   539 // boilerplate
   540 //-----------------------------------------------------------------------
   542 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(NFSubstitution)
   544 /**
   545  * Compares two substitutions for equality
   546  * @param The substitution to compare this one to
   547  * @return true if the two substitutions are functionally equivalent
   548  */
   549 UBool
   550 NFSubstitution::operator==(const NFSubstitution& rhs) const
   551 {
   552   // compare class and all of the fields all substitutions have
   553   // in common
   554   // this should be called by subclasses before their own equality tests
   555   return typeid(*this) == typeid(rhs)
   556   && pos == rhs.pos
   557   && (ruleSet == NULL) == (rhs.ruleSet == NULL)
   558   // && ruleSet == rhs.ruleSet causes circularity, other checks to make instead?
   559   && (numberFormat == NULL
   560       ? (rhs.numberFormat == NULL)
   561       : (*numberFormat == *rhs.numberFormat));
   562 }
   564 /**
   565  * Returns a textual description of the substitution
   566  * @return A textual description of the substitution.  This might
   567  * not be identical to the description it was created from, but
   568  * it'll produce the same result.
   569  */
   570 void
   571 NFSubstitution::toString(UnicodeString& text) const
   572 {
   573   // use tokenChar() to get the character at the beginning and
   574   // end of the substitutin token.  In between them will go
   575   // either the name of the rule set it uses, or the pattern of
   576   // the DecimalFormat it uses
   577   text.remove();
   578   text.append(tokenChar());
   580   UnicodeString temp;
   581   if (ruleSet != NULL) {
   582     ruleSet->getName(temp);
   583   } else if (numberFormat != NULL) {
   584     numberFormat->toPattern(temp);
   585   }
   586   text.append(temp);
   587   text.append(tokenChar());
   588 }
   590 //-----------------------------------------------------------------------
   591 // formatting
   592 //-----------------------------------------------------------------------
   594 /**
   595  * Performs a mathematical operation on the number, formats it using
   596  * either ruleSet or decimalFormat, and inserts the result into
   597  * toInsertInto.
   598  * @param number The number being formatted.
   599  * @param toInsertInto The string we insert the result into
   600  * @param pos The position in toInsertInto where the owning rule's
   601  * rule text begins (this value is added to this substitution's
   602  * position to determine exactly where to insert the new text)
   603  */
   604 void
   605 NFSubstitution::doSubstitution(int64_t number, UnicodeString& toInsertInto, int32_t _pos) const
   606 {
   607     if (ruleSet != NULL) {
   608         // perform a transformation on the number that is dependent
   609         // on the type of substitution this is, then just call its
   610         // rule set's format() method to format the result
   611         ruleSet->format(transformNumber(number), toInsertInto, _pos + this->pos);
   612     } else if (numberFormat != NULL) {
   613         // or perform the transformation on the number (preserving
   614         // the result's fractional part if the formatter it set
   615         // to show it), then use that formatter's format() method
   616         // to format the result
   617         double numberToFormat = transformNumber((double)number);
   618         if (numberFormat->getMaximumFractionDigits() == 0) {
   619             numberToFormat = uprv_floor(numberToFormat);
   620         }
   622         UnicodeString temp;
   623         numberFormat->format(numberToFormat, temp);
   624         toInsertInto.insert(_pos + this->pos, temp);
   625     }
   626 }
   628 /**
   629  * Performs a mathematical operation on the number, formats it using
   630  * either ruleSet or decimalFormat, and inserts the result into
   631  * toInsertInto.
   632  * @param number The number being formatted.
   633  * @param toInsertInto The string we insert the result into
   634  * @param pos The position in toInsertInto where the owning rule's
   635  * rule text begins (this value is added to this substitution's
   636  * position to determine exactly where to insert the new text)
   637  */
   638 void
   639 NFSubstitution::doSubstitution(double number, UnicodeString& toInsertInto, int32_t _pos) const {
   640     // perform a transformation on the number being formatted that
   641     // is dependent on the type of substitution this is
   642     double numberToFormat = transformNumber(number);
   644     // if the result is an integer, from here on out we work in integer
   645     // space (saving time and memory and preserving accuracy)
   646     if (numberToFormat == uprv_floor(numberToFormat) && ruleSet != NULL) {
   647         ruleSet->format(util64_fromDouble(numberToFormat), toInsertInto, _pos + this->pos);
   649         // if the result isn't an integer, then call either our rule set's
   650         // format() method or our DecimalFormat's format() method to
   651         // format the result
   652     } else {
   653         if (ruleSet != NULL) {
   654             ruleSet->format(numberToFormat, toInsertInto, _pos + this->pos);
   655         } else if (numberFormat != NULL) {
   656             UnicodeString temp;
   657             numberFormat->format(numberToFormat, temp);
   658             toInsertInto.insert(_pos + this->pos, temp);
   659         }
   660     }
   661 }
   664     //-----------------------------------------------------------------------
   665     // parsing
   666     //-----------------------------------------------------------------------
   668 #ifdef RBNF_DEBUG
   669 #include <stdio.h>
   670 #endif
   672 /**
   673  * Parses a string using the rule set or DecimalFormat belonging
   674  * to this substitution.  If there's a match, a mathematical
   675  * operation (the inverse of the one used in formatting) is
   676  * performed on the result of the parse and the value passed in
   677  * and returned as the result.  The parse position is updated to
   678  * point to the first unmatched character in the string.
   679  * @param text The string to parse
   680  * @param parsePosition On entry, ignored, but assumed to be 0.
   681  * On exit, this is updated to point to the first unmatched
   682  * character (or 0 if the substitution didn't match)
   683  * @param baseValue A partial parse result that should be
   684  * combined with the result of this parse
   685  * @param upperBound When searching the rule set for a rule
   686  * matching the string passed in, only rules with base values
   687  * lower than this are considered
   688  * @param lenientParse If true and matching against rules fails,
   689  * the substitution will also try matching the text against
   690  * numerals using a default-costructed NumberFormat.  If false,
   691  * no extra work is done.  (This value is false whenever the
   692  * formatter isn't in lenient-parse mode, but is also false
   693  * under some conditions even when the formatter _is_ in
   694  * lenient-parse mode.)
   695  * @return If there's a match, this is the result of composing
   696  * baseValue with whatever was returned from matching the
   697  * characters.  This will be either a Long or a Double.  If there's
   698  * no match this is new Long(0) (not null), and parsePosition
   699  * is left unchanged.
   700  */
   701 UBool
   702 NFSubstitution::doParse(const UnicodeString& text,
   703                         ParsePosition& parsePosition,
   704                         double baseValue,
   705                         double upperBound,
   706                         UBool lenientParse,
   707                         Formattable& result) const
   708 {
   709 #ifdef RBNF_DEBUG
   710     fprintf(stderr, "<nfsubs> %x bv: %g ub: %g\n", this, baseValue, upperBound);
   711 #endif
   712     // figure out the highest base value a rule can have and match
   713     // the text being parsed (this varies according to the type of
   714     // substitutions: multiplier, modulus, and numerator substitutions
   715     // restrict the search to rules with base values lower than their
   716     // own; same-value substitutions leave the upper bound wherever
   717     // it was, and the others allow any rule to match
   718     upperBound = calcUpperBound(upperBound);
   720     // use our rule set to parse the text.  If that fails and
   721     // lenient parsing is enabled (this is always false if the
   722     // formatter's lenient-parsing mode is off, but it may also
   723     // be false even when the formatter's lenient-parse mode is
   724     // on), then also try parsing the text using a default-
   725     // constructed NumberFormat
   726     if (ruleSet != NULL) {
   727         ruleSet->parse(text, parsePosition, upperBound, result);
   728         if (lenientParse && !ruleSet->isFractionRuleSet() && parsePosition.getIndex() == 0) {
   729             UErrorCode status = U_ZERO_ERROR;
   730             NumberFormat* fmt = NumberFormat::createInstance(status);
   731             if (U_SUCCESS(status)) {
   732                 fmt->parse(text, result, parsePosition);
   733             }
   734             delete fmt;
   735         }
   737         // ...or use our DecimalFormat to parse the text
   738     } else if (numberFormat != NULL) {
   739         numberFormat->parse(text, result, parsePosition);
   740     }
   742     // if the parse was successful, we've already advanced the caller's
   743     // parse position (this is the one function that doesn't have one
   744     // of its own).  Derive a parse result and return it as a Long,
   745     // if possible, or a Double
   746     if (parsePosition.getIndex() != 0) {
   747         UErrorCode status = U_ZERO_ERROR;
   748         double tempResult = result.getDouble(status);
   750         // composeRuleValue() produces a full parse result from
   751         // the partial parse result passed to this function from
   752         // the caller (this is either the owning rule's base value
   753         // or the partial result obtained from composing the
   754         // owning rule's base value with its other substitution's
   755         // parse result) and the partial parse result obtained by
   756         // matching the substitution (which will be the same value
   757         // the caller would get by parsing just this part of the
   758         // text with RuleBasedNumberFormat.parse() ).  How the two
   759         // values are used to derive the full parse result depends
   760         // on the types of substitutions: For a regular rule, the
   761         // ultimate result is its multiplier substitution's result
   762         // times the rule's divisor (or the rule's base value) plus
   763         // the modulus substitution's result (which will actually
   764         // supersede part of the rule's base value).  For a negative-
   765         // number rule, the result is the negative of its substitution's
   766         // result.  For a fraction rule, it's the sum of its two
   767         // substitution results.  For a rule in a fraction rule set,
   768         // it's the numerator substitution's result divided by
   769         // the rule's base value.  Results from same-value substitutions
   770         // propagate back upard, and null substitutions don't affect
   771         // the result.
   772         tempResult = composeRuleValue(tempResult, baseValue);
   773         result.setDouble(tempResult);
   774         return TRUE;
   775         // if the parse was UNsuccessful, return 0
   776     } else {
   777         result.setLong(0);
   778         return FALSE;
   779     }
   780 }
   782 UBool
   783 NFSubstitution::isNullSubstitution() const {
   784     return FALSE;
   785 }
   787     /**
   788      * Returns true if this is a modulus substitution.  (We didn't do this
   789      * with instanceof partially because it causes source files to
   790      * proliferate and partially because we have to port this to C++.)
   791      * @return true if this object is an instance of ModulusSubstitution
   792      */
   793 UBool
   794 NFSubstitution::isModulusSubstitution() const {
   795     return FALSE;
   796 }
   798 //===================================================================
   799 // SameValueSubstitution
   800 //===================================================================
   802 /**
   803  * A substitution that passes the value passed to it through unchanged.
   804  * Represented by == in rule descriptions.
   805  */
   806 SameValueSubstitution::SameValueSubstitution(int32_t _pos,
   807                         const NFRuleSet* _ruleSet,
   808                         const RuleBasedNumberFormat* formatter,
   809                         const UnicodeString& description,
   810                         UErrorCode& status)
   811 : NFSubstitution(_pos, _ruleSet, formatter, description, status)
   812 {
   813     if (0 == description.compare(gEqualsEquals, 2)) {
   814         // throw new IllegalArgumentException("== is not a legal token");
   815         status = U_PARSE_ERROR;
   816     }
   817 }
   819 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(SameValueSubstitution)
   821 //===================================================================
   822 // MultiplierSubstitution
   823 //===================================================================
   825 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(MultiplierSubstitution)
   827 UBool MultiplierSubstitution::operator==(const NFSubstitution& rhs) const
   828 {
   829     return NFSubstitution::operator==(rhs) &&
   830         divisor == ((const MultiplierSubstitution*)&rhs)->divisor;
   831 }
   834 //===================================================================
   835 // ModulusSubstitution
   836 //===================================================================
   838 /**
   839  * A substitution that divides the number being formatted by the its rule's
   840  * divisor and formats the remainder.  Represented by "&gt;&gt;" in a
   841  * regular rule.
   842  */
   843 ModulusSubstitution::ModulusSubstitution(int32_t _pos,
   844                                          double _divisor,
   845                                          const NFRule* predecessor,
   846                                          const NFRuleSet* _ruleSet,
   847                                          const RuleBasedNumberFormat* formatter,
   848                                          const UnicodeString& description,
   849                                          UErrorCode& status)
   850  : NFSubstitution(_pos, _ruleSet, formatter, description, status)
   851  , divisor(_divisor)
   852  , ruleToUse(NULL)
   853 {
   854   ldivisor = util64_fromDouble(_divisor);
   856   // the owning rule's divisor controls the behavior of this
   857   // substitution: rather than keeping a backpointer to the rule,
   858   // we keep a copy of the divisor
   860   if (ldivisor == 0) {
   861       status = U_PARSE_ERROR;
   862   }
   864   if (0 == description.compare(gGreaterGreaterGreaterThan, 3)) {
   865     // the >>> token doesn't alter how this substituion calculates the
   866     // values it uses for formatting and parsing, but it changes
   867     // what's done with that value after it's obtained: >>> short-
   868     // circuits the rule-search process and goes straight to the
   869     // specified rule to format the substitution value
   870     ruleToUse = predecessor;
   871   }
   872 }
   874 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(ModulusSubstitution)
   876 UBool ModulusSubstitution::operator==(const NFSubstitution& rhs) const
   877 {
   878   return NFSubstitution::operator==(rhs) &&
   879   divisor == ((const ModulusSubstitution*)&rhs)->divisor &&
   880   ruleToUse == ((const ModulusSubstitution*)&rhs)->ruleToUse;
   881 }
   883 //-----------------------------------------------------------------------
   884 // formatting
   885 //-----------------------------------------------------------------------
   888 /**
   889  * If this is a &gt;&gt;&gt; substitution, use ruleToUse to fill in
   890  * the substitution.  Otherwise, just use the superclass function.
   891  * @param number The number being formatted
   892  * @toInsertInto The string to insert the result of this substitution
   893  * into
   894  * @param pos The position of the rule text in toInsertInto
   895  */
   896 void
   897 ModulusSubstitution::doSubstitution(int64_t number, UnicodeString& toInsertInto, int32_t _pos) const
   898 {
   899     // if this isn't a >>> substitution, just use the inherited version
   900     // of this function (which uses either a rule set or a DecimalFormat
   901     // to format its substitution value)
   902     if (ruleToUse == NULL) {
   903         NFSubstitution::doSubstitution(number, toInsertInto, _pos);
   905         // a >>> substitution goes straight to a particular rule to
   906         // format the substitution value
   907     } else {
   908         int64_t numberToFormat = transformNumber(number);
   909         ruleToUse->doFormat(numberToFormat, toInsertInto, _pos + getPos());
   910     }
   911 }
   913 /**
   914 * If this is a &gt;&gt;&gt; substitution, use ruleToUse to fill in
   915 * the substitution.  Otherwise, just use the superclass function.
   916 * @param number The number being formatted
   917 * @toInsertInto The string to insert the result of this substitution
   918 * into
   919 * @param pos The position of the rule text in toInsertInto
   920 */
   921 void
   922 ModulusSubstitution::doSubstitution(double number, UnicodeString& toInsertInto, int32_t _pos) const
   923 {
   924     // if this isn't a >>> substitution, just use the inherited version
   925     // of this function (which uses either a rule set or a DecimalFormat
   926     // to format its substitution value)
   927     if (ruleToUse == NULL) {
   928         NFSubstitution::doSubstitution(number, toInsertInto, _pos);
   930         // a >>> substitution goes straight to a particular rule to
   931         // format the substitution value
   932     } else {
   933         double numberToFormat = transformNumber(number);
   935         ruleToUse->doFormat(numberToFormat, toInsertInto, _pos + getPos());
   936     }
   937 }
   939 //-----------------------------------------------------------------------
   940 // parsing
   941 //-----------------------------------------------------------------------
   943 /**
   944  * If this is a &gt;&gt;&gt; substitution, match only against ruleToUse.
   945  * Otherwise, use the superclass function.
   946  * @param text The string to parse
   947  * @param parsePosition Ignored on entry, updated on exit to point to
   948  * the first unmatched character.
   949  * @param baseValue The partial parse result prior to calling this
   950  * routine.
   951  */
   952 UBool
   953 ModulusSubstitution::doParse(const UnicodeString& text,
   954                              ParsePosition& parsePosition,
   955                              double baseValue,
   956                              double upperBound,
   957                              UBool lenientParse,
   958                              Formattable& result) const
   959 {
   960     // if this isn't a >>> substitution, we can just use the
   961     // inherited parse() routine to do the parsing
   962     if (ruleToUse == NULL) {
   963         return NFSubstitution::doParse(text, parsePosition, baseValue, upperBound, lenientParse, result);
   965         // but if it IS a >>> substitution, we have to do it here: we
   966         // use the specific rule's doParse() method, and then we have to
   967         // do some of the other work of NFRuleSet.parse()
   968     } else {
   969         ruleToUse->doParse(text, parsePosition, FALSE, upperBound, result);
   971         if (parsePosition.getIndex() != 0) {
   972             UErrorCode status = U_ZERO_ERROR;
   973             double tempResult = result.getDouble(status);
   974             tempResult = composeRuleValue(tempResult, baseValue);
   975             result.setDouble(tempResult);
   976         }
   978         return TRUE;
   979     }
   980 }
   981 /**
   982  * Returns a textual description of the substitution
   983  * @return A textual description of the substitution.  This might
   984  * not be identical to the description it was created from, but
   985  * it'll produce the same result.
   986  */
   987 void
   988 ModulusSubstitution::toString(UnicodeString& text) const
   989 {
   990   // use tokenChar() to get the character at the beginning and
   991   // end of the substitutin token.  In between them will go
   992   // either the name of the rule set it uses, or the pattern of
   993   // the DecimalFormat it uses
   995   if ( ruleToUse != NULL ) { // Must have been a >>> substitution.
   996       text.remove();
   997       text.append(tokenChar());
   998       text.append(tokenChar());
   999       text.append(tokenChar());
  1000   } else { // Otherwise just use the super-class function.
  1001 	  NFSubstitution::toString(text);
  1004 //===================================================================
  1005 // IntegralPartSubstitution
  1006 //===================================================================
  1008 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(IntegralPartSubstitution)
  1011 //===================================================================
  1012 // FractionalPartSubstitution
  1013 //===================================================================
  1016     /**
  1017      * Constructs a FractionalPartSubstitution.  This object keeps a flag
  1018      * telling whether it should format by digits or not.  In addition,
  1019      * it marks the rule set it calls (if any) as a fraction rule set.
  1020      */
  1021 FractionalPartSubstitution::FractionalPartSubstitution(int32_t _pos,
  1022                              const NFRuleSet* _ruleSet,
  1023                              const RuleBasedNumberFormat* formatter,
  1024                              const UnicodeString& description,
  1025                              UErrorCode& status)
  1026  : NFSubstitution(_pos, _ruleSet, formatter, description, status)
  1027  , byDigits(FALSE)
  1028  , useSpaces(TRUE)
  1031     // akk, ruleSet can change in superclass constructor
  1032     if (0 == description.compare(gGreaterGreaterThan, 2) ||
  1033         0 == description.compare(gGreaterGreaterGreaterThan, 3) ||
  1034         _ruleSet == getRuleSet()) {
  1035         byDigits = TRUE;
  1036         if (0 == description.compare(gGreaterGreaterGreaterThan, 3)) {
  1037             useSpaces = FALSE;
  1039     } else {
  1040         // cast away const
  1041         ((NFRuleSet*)getRuleSet())->makeIntoFractionRuleSet();
  1045 //-----------------------------------------------------------------------
  1046 // formatting
  1047 //-----------------------------------------------------------------------
  1049 /**
  1050  * If in "by digits" mode, fills in the substitution one decimal digit
  1051  * at a time using the rule set containing this substitution.
  1052  * Otherwise, uses the superclass function.
  1053  * @param number The number being formatted
  1054  * @param toInsertInto The string to insert the result of formatting
  1055  * the substitution into
  1056  * @param pos The position of the owning rule's rule text in
  1057  * toInsertInto
  1058  */
  1059 void
  1060 FractionalPartSubstitution::doSubstitution(double number, UnicodeString& toInsertInto, int32_t _pos) const
  1062   // if we're not in "byDigits" mode, just use the inherited
  1063   // doSubstitution() routine
  1064   if (!byDigits) {
  1065     NFSubstitution::doSubstitution(number, toInsertInto, _pos);
  1067     // if we're in "byDigits" mode, transform the value into an integer
  1068     // by moving the decimal point eight places to the right and
  1069     // pulling digits off the right one at a time, formatting each digit
  1070     // as an integer using this substitution's owning rule set
  1071     // (this is slower, but more accurate, than doing it from the
  1072     // other end)
  1073   } else {
  1074     //          int32_t numberToFormat = (int32_t)uprv_round(transformNumber(number) * uprv_pow(10, kMaxDecimalDigits));
  1075     //          // this flag keeps us from formatting trailing zeros.  It starts
  1076     //          // out false because we're pulling from the right, and switches
  1077     //          // to true the first time we encounter a non-zero digit
  1078     //          UBool doZeros = FALSE;
  1079     //          for (int32_t i = 0; i < kMaxDecimalDigits; i++) {
  1080     //              int64_t digit = numberToFormat % 10;
  1081     //              if (digit != 0 || doZeros) {
  1082     //                  if (doZeros && useSpaces) {
  1083     //                      toInsertInto.insert(_pos + getPos(), gSpace);
  1084     //                  }
  1085     //                  doZeros = TRUE;
  1086     //                  getRuleSet()->format(digit, toInsertInto, _pos + getPos());
  1087     //              }
  1088     //              numberToFormat /= 10;
  1089     //          }
  1091     DigitList dl;
  1092     dl.set(number);
  1093     dl.roundFixedPoint(20);     // round to 20 fraction digits.
  1094     dl.reduce();                // Removes any trailing zeros.
  1096     UBool pad = FALSE;
  1097     for (int32_t didx = dl.getCount()-1; didx>=dl.getDecimalAt(); didx--) {
  1098       // Loop iterates over fraction digits, starting with the LSD.
  1099       //   include both real digits from the number, and zeros
  1100       //   to the left of the MSD but to the right of the decimal point.
  1101       if (pad && useSpaces) {
  1102         toInsertInto.insert(_pos + getPos(), gSpace);
  1103       } else {
  1104         pad = TRUE;
  1106       int64_t digit = didx>=0 ? dl.getDigit(didx) - '0' : 0;
  1107       getRuleSet()->format(digit, toInsertInto, _pos + getPos());
  1110     if (!pad) {
  1111       // hack around lack of precision in digitlist. if we would end up with
  1112       // "foo point" make sure we add a " zero" to the end.
  1113       getRuleSet()->format((int64_t)0, toInsertInto, _pos + getPos());
  1118 //-----------------------------------------------------------------------
  1119 // parsing
  1120 //-----------------------------------------------------------------------
  1122 /**
  1123  * If in "by digits" mode, parses the string as if it were a string
  1124  * of individual digits; otherwise, uses the superclass function.
  1125  * @param text The string to parse
  1126  * @param parsePosition Ignored on entry, but updated on exit to point
  1127  * to the first unmatched character
  1128  * @param baseValue The partial parse result prior to entering this
  1129  * function
  1130  * @param upperBound Only consider rules with base values lower than
  1131  * this when filling in the substitution
  1132  * @param lenientParse If true, try matching the text as numerals if
  1133  * matching as words doesn't work
  1134  * @return If the match was successful, the current partial parse
  1135  * result; otherwise new Long(0).  The result is either a Long or
  1136  * a Double.
  1137  */
  1139 UBool
  1140 FractionalPartSubstitution::doParse(const UnicodeString& text,
  1141                 ParsePosition& parsePosition,
  1142                 double baseValue,
  1143                 double /*upperBound*/,
  1144                 UBool lenientParse,
  1145                 Formattable& resVal) const
  1147     // if we're not in byDigits mode, we can just use the inherited
  1148     // doParse()
  1149     if (!byDigits) {
  1150         return NFSubstitution::doParse(text, parsePosition, baseValue, 0, lenientParse, resVal);
  1152         // if we ARE in byDigits mode, parse the text one digit at a time
  1153         // using this substitution's owning rule set (we do this by setting
  1154         // upperBound to 10 when calling doParse() ) until we reach
  1155         // nonmatching text
  1156     } else {
  1157         UnicodeString workText(text);
  1158         ParsePosition workPos(1);
  1159         double result = 0;
  1160         int32_t digit;
  1161 //          double p10 = 0.1;
  1163         DigitList dl;
  1164         NumberFormat* fmt = NULL;
  1165         while (workText.length() > 0 && workPos.getIndex() != 0) {
  1166             workPos.setIndex(0);
  1167             Formattable temp;
  1168             getRuleSet()->parse(workText, workPos, 10, temp);
  1169             UErrorCode status = U_ZERO_ERROR;
  1170             digit = temp.getLong(status);
  1171 //            digit = temp.getType() == Formattable::kLong ?
  1172 //               temp.getLong() :
  1173 //            (int32_t)temp.getDouble();
  1175             if (lenientParse && workPos.getIndex() == 0) {
  1176                 if (!fmt) {
  1177                     status = U_ZERO_ERROR;
  1178                     fmt = NumberFormat::createInstance(status);
  1179                     if (U_FAILURE(status)) {
  1180                         delete fmt;
  1181                         fmt = NULL;
  1184                 if (fmt) {
  1185                     fmt->parse(workText, temp, workPos);
  1186                     digit = temp.getLong(status);
  1190             if (workPos.getIndex() != 0) {
  1191                 dl.append((char)('0' + digit));
  1192 //                  result += digit * p10;
  1193 //                  p10 /= 10;
  1194                 parsePosition.setIndex(parsePosition.getIndex() + workPos.getIndex());
  1195                 workText.removeBetween(0, workPos.getIndex());
  1196                 while (workText.length() > 0 && workText.charAt(0) == gSpace) {
  1197                     workText.removeBetween(0, 1);
  1198                     parsePosition.setIndex(parsePosition.getIndex() + 1);
  1202         delete fmt;
  1204         result = dl.getCount() == 0 ? 0 : dl.getDouble();
  1205         result = composeRuleValue(result, baseValue);
  1206         resVal.setDouble(result);
  1207         return TRUE;
  1211 UBool
  1212 FractionalPartSubstitution::operator==(const NFSubstitution& rhs) const
  1214   return NFSubstitution::operator==(rhs) &&
  1215   ((const FractionalPartSubstitution*)&rhs)->byDigits == byDigits;
  1218 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(FractionalPartSubstitution)
  1221 //===================================================================
  1222 // AbsoluteValueSubstitution
  1223 //===================================================================
  1225 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(AbsoluteValueSubstitution)
  1227 //===================================================================
  1228 // NumeratorSubstitution
  1229 //===================================================================
  1231 void
  1232 NumeratorSubstitution::doSubstitution(double number, UnicodeString& toInsertInto, int32_t apos) const {
  1233     // perform a transformation on the number being formatted that
  1234     // is dependent on the type of substitution this is
  1236     double numberToFormat = transformNumber(number);
  1237     int64_t longNF = util64_fromDouble(numberToFormat);
  1239     const NFRuleSet* aruleSet = getRuleSet();
  1240     if (withZeros && aruleSet != NULL) {
  1241         // if there are leading zeros in the decimal expansion then emit them
  1242         int64_t nf =longNF;
  1243         int32_t len = toInsertInto.length();
  1244         while ((nf *= 10) < denominator) {
  1245             toInsertInto.insert(apos + getPos(), gSpace);
  1246             aruleSet->format((int64_t)0, toInsertInto, apos + getPos());
  1248         apos += toInsertInto.length() - len;
  1251     // if the result is an integer, from here on out we work in integer
  1252     // space (saving time and memory and preserving accuracy)
  1253     if (numberToFormat == longNF && aruleSet != NULL) {
  1254         aruleSet->format(longNF, toInsertInto, apos + getPos());
  1256         // if the result isn't an integer, then call either our rule set's
  1257         // format() method or our DecimalFormat's format() method to
  1258         // format the result
  1259     } else {
  1260         if (aruleSet != NULL) {
  1261             aruleSet->format(numberToFormat, toInsertInto, apos + getPos());
  1262         } else {
  1263             UErrorCode status = U_ZERO_ERROR;
  1264             UnicodeString temp;
  1265             getNumberFormat()->format(numberToFormat, temp, status);
  1266             toInsertInto.insert(apos + getPos(), temp);
  1271 UBool 
  1272 NumeratorSubstitution::doParse(const UnicodeString& text, 
  1273                                ParsePosition& parsePosition,
  1274                                double baseValue,
  1275                                double upperBound,
  1276                                UBool /*lenientParse*/,
  1277                                Formattable& result) const
  1279     // we don't have to do anything special to do the parsing here,
  1280     // but we have to turn lenient parsing off-- if we leave it on,
  1281     // it SERIOUSLY messes up the algorithm
  1283     // if withZeros is true, we need to count the zeros
  1284     // and use that to adjust the parse result
  1285     UErrorCode status = U_ZERO_ERROR;
  1286     int32_t zeroCount = 0;
  1287     UnicodeString workText(text);
  1289     if (withZeros) {
  1290         ParsePosition workPos(1);
  1291         Formattable temp;
  1293         while (workText.length() > 0 && workPos.getIndex() != 0) {
  1294             workPos.setIndex(0);
  1295             getRuleSet()->parse(workText, workPos, 1, temp); // parse zero or nothing at all
  1296             if (workPos.getIndex() == 0) {
  1297                 // we failed, either there were no more zeros, or the number was formatted with digits
  1298                 // either way, we're done
  1299                 break;
  1302             ++zeroCount;
  1303             parsePosition.setIndex(parsePosition.getIndex() + workPos.getIndex());
  1304             workText.remove(0, workPos.getIndex());
  1305             while (workText.length() > 0 && workText.charAt(0) == gSpace) {
  1306                 workText.remove(0, 1);
  1307                 parsePosition.setIndex(parsePosition.getIndex() + 1);
  1311         workText = text;
  1312         workText.remove(0, (int32_t)parsePosition.getIndex());
  1313         parsePosition.setIndex(0);
  1316     // we've parsed off the zeros, now let's parse the rest from our current position
  1317     NFSubstitution::doParse(workText, parsePosition, withZeros ? 1 : baseValue, upperBound, FALSE, result);
  1319     if (withZeros) {
  1320         // any base value will do in this case.  is there a way to
  1321         // force this to not bother trying all the base values?
  1323         // compute the 'effective' base and prescale the value down
  1324         int64_t n = result.getLong(status); // force conversion!
  1325         int64_t d = 1;
  1326         int32_t pow = 0;
  1327         while (d <= n) {
  1328             d *= 10;
  1329             ++pow;
  1331         // now add the zeros
  1332         while (zeroCount > 0) {
  1333             d *= 10;
  1334             --zeroCount;
  1336         // d is now our true denominator
  1337         result.setDouble((double)n/(double)d);
  1340     return TRUE;
  1343 UBool
  1344 NumeratorSubstitution::operator==(const NFSubstitution& rhs) const
  1346     return NFSubstitution::operator==(rhs) &&
  1347         denominator == ((const NumeratorSubstitution*)&rhs)->denominator;
  1350 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(NumeratorSubstitution)
  1352 const UChar NumeratorSubstitution::LTLT[] = { 0x003c, 0x003c };
  1354 //===================================================================
  1355 // NullSubstitution
  1356 //===================================================================
  1358 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(NullSubstitution)
  1360 U_NAMESPACE_END
  1362 /* U_HAVE_RBNF */
  1363 #endif

mercurial