]> git.saurik.com Git - apple/icu.git/blobdiff - icuSources/i18n/nfsubs.cpp
ICU-491.11.2.tar.gz
[apple/icu.git] / icuSources / i18n / nfsubs.cpp
index 37de55a4a1cbb7e46dbe247b32280cb5a2e0a881..d02c9e15ce4f91c8d382058432f3959c56ad4d2c 100644 (file)
@@ -1,6 +1,6 @@
 /*
 ******************************************************************************
-*   Copyright (C) 1997-2007, International Business Machines
+*   Copyright (C) 1997-2011, International Business Machines
 *   Corporation and others.  All Rights Reserved.
 ******************************************************************************
 *   file name:  nfsubs.cpp
 * 10/11/2001  Doug      Ported from ICU4J
 */
 
+#include <stdio.h>
+#include <typeinfo>  // for 'typeid' to work
+
 #include "nfsubs.h"
 #include "digitlst.h"
 
-#include <stdio.h>
-
 #if U_HAVE_RBNF
 
 static const UChar gLessThan = 0x003c;
@@ -50,6 +51,7 @@ public:
         const RuleBasedNumberFormat* formatter,
         const UnicodeString& description,
         UErrorCode& status);
+    virtual ~SameValueSubstitution();
 
     virtual int64_t transformNumber(int64_t number) const { return number; }
     virtual double transformNumber(double number) const { return number; }
@@ -62,6 +64,8 @@ public:
     virtual UClassID getDynamicClassID(void) const;
 };
 
+SameValueSubstitution::~SameValueSubstitution() {}
+
 class MultiplierSubstitution : public NFSubstitution {
     double divisor;
     int64_t ldivisor;
@@ -80,6 +84,7 @@ public:
             status = U_PARSE_ERROR;
         }
     }
+    virtual ~MultiplierSubstitution();
 
     virtual void setDivisor(int32_t radix, int32_t exponent, UErrorCode& status) { 
         divisor = uprv_pow(radix, exponent);
@@ -117,6 +122,8 @@ public:
     virtual UClassID getDynamicClassID(void) const;
 };
 
+MultiplierSubstitution::~MultiplierSubstitution() {}
+
 class ModulusSubstitution : public NFSubstitution {
     double divisor;
     int64_t  ldivisor;
@@ -129,6 +136,7 @@ public:
         const RuleBasedNumberFormat* formatter,
         const UnicodeString& description,
         UErrorCode& status);
+    virtual ~ModulusSubstitution();
 
     virtual void setDivisor(int32_t radix, int32_t exponent, UErrorCode& status) { 
         divisor = uprv_pow(radix, exponent);
@@ -164,11 +172,15 @@ public:
 
     virtual UChar tokenChar() const { return (UChar)0x003e; } // '>'
 
+       virtual void toString(UnicodeString& result) const;
+
 public:
     static UClassID getStaticClassID(void);
     virtual UClassID getDynamicClassID(void) const;
 };
 
+ModulusSubstitution::~ModulusSubstitution() {}
+
 class IntegralPartSubstitution : public NFSubstitution {
 public:
     IntegralPartSubstitution(int32_t _pos,
@@ -177,6 +189,7 @@ public:
         const UnicodeString& description,
         UErrorCode& status)
         : NFSubstitution(_pos, _ruleSet, formatter, description, status) {}
+    virtual ~IntegralPartSubstitution();
 
     virtual int64_t transformNumber(int64_t number) const { return number; }
     virtual double transformNumber(double number) const { return uprv_floor(number); }
@@ -189,6 +202,8 @@ public:
     virtual UClassID getDynamicClassID(void) const;
 };
 
+IntegralPartSubstitution::~IntegralPartSubstitution() {}
+
 class FractionalPartSubstitution : public NFSubstitution {
     UBool byDigits;
     UBool useSpaces;
@@ -199,6 +214,7 @@ public:
         const RuleBasedNumberFormat* formatter,
         const UnicodeString& description,
         UErrorCode& status);
+    virtual ~FractionalPartSubstitution();
 
     virtual UBool operator==(const NFSubstitution& rhs) const;
 
@@ -223,6 +239,8 @@ public:
     virtual UClassID getDynamicClassID(void) const;
 };
 
+FractionalPartSubstitution::~FractionalPartSubstitution() {}
+
 class AbsoluteValueSubstitution : public NFSubstitution {
 public:
     AbsoluteValueSubstitution(int32_t _pos,
@@ -231,6 +249,7 @@ public:
         const UnicodeString& description,
         UErrorCode& status)
         : NFSubstitution(_pos, _ruleSet, formatter, description, status) {}
+    virtual ~AbsoluteValueSubstitution();
 
     virtual int64_t transformNumber(int64_t number) const { return number >= 0 ? number : -number; }
     virtual double transformNumber(double number) const { return uprv_fabs(number); }
@@ -243,6 +262,8 @@ public:
     virtual UClassID getDynamicClassID(void) const;
 };
 
+AbsoluteValueSubstitution::~AbsoluteValueSubstitution() {}
+
 class NumeratorSubstitution : public NFSubstitution {
     double denominator;
     int64_t ldenominator;
@@ -266,6 +287,7 @@ public:
         ldenominator = util64_fromDouble(denominator);
         withZeros = description.endsWith(LTLT, 2);
     }
+    virtual ~NumeratorSubstitution();
 
     virtual UBool operator==(const NFSubstitution& rhs) const;
 
@@ -292,6 +314,8 @@ public:
     virtual UClassID getDynamicClassID(void) const;
 };
 
+NumeratorSubstitution::~NumeratorSubstitution() {}
+
 class NullSubstitution : public NFSubstitution {
 public:
     NullSubstitution(int32_t _pos,
@@ -300,6 +324,7 @@ public:
         const UnicodeString& description,
         UErrorCode& status)
         : NFSubstitution(_pos, _ruleSet, formatter, description, status) {}
+    virtual ~NullSubstitution();
 
     virtual void toString(UnicodeString& /*result*/) const {}
     virtual void doSubstitution(double /*number*/, UnicodeString& /*toInsertInto*/, int32_t /*_pos*/) const {}
@@ -323,6 +348,8 @@ public:
     virtual UClassID getDynamicClassID(void) const;
 };
 
+NullSubstitution::~NullSubstitution() {}
+
 NFSubstitution*
 NFSubstitution::makeSubstitution(int32_t pos,
                                  const NFRule* rule,
@@ -525,7 +552,7 @@ NFSubstitution::operator==(const NFSubstitution& rhs) const
   // compare class and all of the fields all substitutions have
   // in common
   // this should be called by subclasses before their own equality tests
-  return getDynamicClassID() == rhs.getDynamicClassID()
+  return typeid(*this) == typeid(rhs)
   && pos == rhs.pos
   && (ruleSet == NULL) == (rhs.ruleSet == NULL)
   // && ruleSet == rhs.ruleSet causes circularity, other checks to make instead?
@@ -613,10 +640,12 @@ NFSubstitution::doSubstitution(double number, UnicodeString& toInsertInto, int32
     // perform a transformation on the number being formatted that
     // is dependent on the type of substitution this is
     double numberToFormat = transformNumber(number);
+    DigitList digits;
+    digits.set(numberToFormat);
 
     // if the result is an integer, from here on out we work in integer
     // space (saving time and memory and preserving accuracy)
-    if (numberToFormat == uprv_floor(numberToFormat) && ruleSet != NULL) {
+    if (numberToFormat == uprv_floor(numberToFormat) && ruleSet != NULL && (!digits.isInfinite())) {
         ruleSet->format(util64_fromDouble(numberToFormat), toInsertInto, _pos + this->pos);
 
         // if the result isn't an integer, then call either our rule set's
@@ -768,6 +797,22 @@ NFSubstitution::isModulusSubstitution() const {
     return FALSE;
 }
 
+    /**
+     * @return true if this is a decimal format-only substitution
+     */
+UBool
+NFSubstitution::isDecimalFormatSubstitutionOnly() const {
+    return (ruleSet == NULL && getNumberFormat() != NULL);
+}
+
+    /**
+     * @return true if this substitution uses another ruleSet
+     */
+UBool
+NFSubstitution::isRuleSetSubstitutionOnly() const {
+    return (getNumberFormat() == NULL && ruleSet != NULL);
+}
+
 //===================================================================
 // SameValueSubstitution
 //===================================================================
@@ -783,7 +828,7 @@ SameValueSubstitution::SameValueSubstitution(int32_t _pos,
                         UErrorCode& status)
 : NFSubstitution(_pos, _ruleSet, formatter, description, status)
 {
-    if (description == gEqualsEquals) {
+    if (0 == description.compare(gEqualsEquals, 2)) {
         // throw new IllegalArgumentException("== is not a legal token");
         status = U_PARSE_ERROR;
     }
@@ -834,7 +879,7 @@ ModulusSubstitution::ModulusSubstitution(int32_t _pos,
       status = U_PARSE_ERROR;
   }
 
-  if (description == gGreaterGreaterGreaterThan) {
+  if (0 == description.compare(gGreaterGreaterGreaterThan, 3)) {
     // the >>> token doesn't alter how this substituion calculates the
     // values it uses for formatting and parsing, but it changes
     // what's done with that value after it's obtained: >>> short-
@@ -951,8 +996,29 @@ ModulusSubstitution::doParse(const UnicodeString& text,
         return TRUE;
     }
 }
+/**
+ * Returns a textual description of the substitution
+ * @return A textual description of the substitution.  This might
+ * not be identical to the description it was created from, but
+ * it'll produce the same result.
+ */
+void
+ModulusSubstitution::toString(UnicodeString& text) const
+{
+  // use tokenChar() to get the character at the beginning and
+  // end of the substitutin token.  In between them will go
+  // either the name of the rule set it uses, or the pattern of
+  // the DecimalFormat it uses
 
-
+  if ( ruleToUse != NULL ) { // Must have been a >>> substitution.
+      text.remove();
+      text.append(tokenChar());
+      text.append(tokenChar());
+      text.append(tokenChar());
+  } else { // Otherwise just use the super-class function.
+         NFSubstitution::toString(text);
+  }
+}
 //===================================================================
 // IntegralPartSubstitution
 //===================================================================
@@ -981,11 +1047,11 @@ FractionalPartSubstitution::FractionalPartSubstitution(int32_t _pos,
 
 {
     // akk, ruleSet can change in superclass constructor
-    if (description == gGreaterGreaterThan ||
-        description == gGreaterGreaterGreaterThan ||
+    if (0 == description.compare(gGreaterGreaterThan, 2) ||
+        0 == description.compare(gGreaterGreaterGreaterThan, 3) ||
         _ruleSet == getRuleSet()) {
         byDigits = TRUE;
-        if (description == gGreaterGreaterGreaterThan) {
+        if (0 == description.compare(gGreaterGreaterGreaterThan, 3)) {
             useSpaces = FALSE;
         }
     } else {
@@ -1041,25 +1107,22 @@ FractionalPartSubstitution::doSubstitution(double number, UnicodeString& toInser
     //          }
 
     DigitList dl;
-    dl.set(number, 20, TRUE);
+    dl.set(number);
+    dl.roundFixedPoint(20);     // round to 20 fraction digits.
+    dl.reduce();                // Removes any trailing zeros.
     
     UBool pad = FALSE;
-    while (dl.fCount > (dl.fDecimalAt <= 0 ? 0 : dl.fDecimalAt)) {
+    for (int32_t didx = dl.getCount()-1; didx>=dl.getDecimalAt(); didx--) {
+      // Loop iterates over fraction digits, starting with the LSD.
+      //   include both real digits from the number, and zeros
+      //   to the left of the MSD but to the right of the decimal point.
       if (pad && useSpaces) {
         toInsertInto.insert(_pos + getPos(), gSpace);
       } else {
         pad = TRUE;
       }
-      getRuleSet()->format((int64_t)(dl.fDigits[--dl.fCount] - '0'), toInsertInto, _pos + getPos());
-    }
-    while (dl.fDecimalAt < 0) {
-      if (pad && useSpaces) {
-        toInsertInto.insert(_pos + getPos(), gSpace);
-      } else {
-        pad = TRUE;
-      }
-      getRuleSet()->format((int64_t)0, toInsertInto, _pos + getPos());
-      ++dl.fDecimalAt;
+      int64_t digit = didx>=0 ? dl.getDigit(didx) - '0' : 0;
+      getRuleSet()->format(digit, toInsertInto, _pos + getPos());
     }
 
     if (!pad) {
@@ -1156,7 +1219,7 @@ FractionalPartSubstitution::doParse(const UnicodeString& text,
         }
         delete fmt;
 
-        result = dl.fCount == 0 ? 0 : dl.getDouble();
+        result = dl.getCount() == 0 ? 0 : dl.getDouble();
         result = composeRuleValue(result, baseValue);
         resVal.setDouble(result);
         return TRUE;