/*
******************************************************************************
-* 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;
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; }
virtual UClassID getDynamicClassID(void) const;
};
+SameValueSubstitution::~SameValueSubstitution() {}
+
class MultiplierSubstitution : public NFSubstitution {
double divisor;
int64_t ldivisor;
status = U_PARSE_ERROR;
}
}
+ virtual ~MultiplierSubstitution();
virtual void setDivisor(int32_t radix, int32_t exponent, UErrorCode& status) {
divisor = uprv_pow(radix, exponent);
virtual UClassID getDynamicClassID(void) const;
};
+MultiplierSubstitution::~MultiplierSubstitution() {}
+
class ModulusSubstitution : public NFSubstitution {
double divisor;
int64_t ldivisor;
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);
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,
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); }
virtual UClassID getDynamicClassID(void) const;
};
+IntegralPartSubstitution::~IntegralPartSubstitution() {}
+
class FractionalPartSubstitution : public NFSubstitution {
UBool byDigits;
UBool useSpaces;
const RuleBasedNumberFormat* formatter,
const UnicodeString& description,
UErrorCode& status);
+ virtual ~FractionalPartSubstitution();
virtual UBool operator==(const NFSubstitution& rhs) const;
virtual UClassID getDynamicClassID(void) const;
};
+FractionalPartSubstitution::~FractionalPartSubstitution() {}
+
class AbsoluteValueSubstitution : public NFSubstitution {
public:
AbsoluteValueSubstitution(int32_t _pos,
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); }
virtual UClassID getDynamicClassID(void) const;
};
+AbsoluteValueSubstitution::~AbsoluteValueSubstitution() {}
+
class NumeratorSubstitution : public NFSubstitution {
double denominator;
int64_t ldenominator;
ldenominator = util64_fromDouble(denominator);
withZeros = description.endsWith(LTLT, 2);
}
+ virtual ~NumeratorSubstitution();
virtual UBool operator==(const NFSubstitution& rhs) const;
virtual UClassID getDynamicClassID(void) const;
};
+NumeratorSubstitution::~NumeratorSubstitution() {}
+
class NullSubstitution : public NFSubstitution {
public:
NullSubstitution(int32_t _pos,
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 {}
virtual UClassID getDynamicClassID(void) const;
};
+NullSubstitution::~NullSubstitution() {}
+
NFSubstitution*
NFSubstitution::makeSubstitution(int32_t pos,
const NFRule* rule,
// 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?
// 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
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
//===================================================================
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;
}
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-
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
//===================================================================
{
// 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 {
// }
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) {
}
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;