ICU-1766 Make RBNF in ICU4C use 64-bit ints

(still need to remove llong.h, llong.cpp and commented-out code)

X-SVN-Rev: 8008
This commit is contained in:
Doug Felt 2002-03-14 00:28:22 +00:00
parent 66bee38a79
commit f3acab9495
13 changed files with 848 additions and 505 deletions

View file

@ -14,6 +14,9 @@
*/
#include "nfrs.h"
#if U_HAVE_RBNF
#include "nfrule.h"
#include "nfrlist.h"
#include "unicode/uchar.h"
@ -30,8 +33,8 @@ U_NAMESPACE_BEGIN
// isn't as much range as we get with longs. We probably still
// want either 64-bit math, or BigInteger.
static llong
util_lcm(llong x, llong y)
static int64_t
util_lcm(int64_t x, int64_t y)
{
x.abs();
y.abs();
@ -41,7 +44,7 @@ util_lcm(llong x, llong y)
} else {
do {
if (x < y) {
llong t = x; x = y; y = t;
int64_t t = x; x = y; y = t;
}
x -= y * (x/y);
} while (x != 0);
@ -54,13 +57,13 @@ util_lcm(llong x, llong y)
/**
* Calculates the least common multiple of x and y.
*/
static llong
util_lcm(llong x, llong y)
static int64_t
util_lcm(int64_t x, int64_t y)
{
// binary gcd algorithm from Knuth, "The Art of Computer Programming,"
// vol. 2, 1st ed., pp. 298-299
llong x1 = x;
llong y1 = y;
int64_t x1 = x;
int64_t y1 = y;
int p2 = 0;
while ((x1 & 1) == 0 && (y1 & 1) == 0) {
@ -69,7 +72,7 @@ util_lcm(llong x, llong y)
y1 >>= 1;
}
llong t;
int64_t t;
if ((x1 & 1) == 1) {
t = -y1;
} else {
@ -88,7 +91,7 @@ util_lcm(llong x, llong y)
t = x1 - y1;
}
llong gcd = x1 << p2;
int64_t gcd = x1 << p2;
// x * y == gcd(x, y) * lcm(x, y)
return x / gcd * y;
@ -187,7 +190,7 @@ NFRuleSet::parseRules(UnicodeString& description, const RuleBasedNumberFormat* o
// were initialized to 0. Make another pass through the list and
// set all those rules' base values. We also remove any special
// rules from the list and put them into their own member variables
llong defaultBaseValue = (int32_t)0;
int64_t defaultBaseValue = 0;
// (this isn't a for loop because we might be deleting items from
// the vector-- we want to make sure we only increment i when
@ -296,7 +299,7 @@ NFRuleSet::operator==(const NFRuleSet& rhs) const
}
void
NFRuleSet::format(llong number, UnicodeString& toAppendTo, int32_t pos) const
NFRuleSet::format(int64_t number, UnicodeString& toAppendTo, int32_t pos) const
{
NFRule *rule = findNormalRule(number);
rule->doFormat(number, toAppendTo, pos);
@ -348,18 +351,18 @@ NFRuleSet::findDoubleRule(double number) const
// and if we haven't yet returned a rule, use findNormalRule()
// to find the applicable rule
llong r = number + 0.5;
int64_t r = util64_fromDouble(number + 0.5);
return findNormalRule(r);
}
NFRule *
NFRuleSet::findNormalRule(llong number) const
NFRuleSet::findNormalRule(int64_t number) const
{
// if this is a fraction rule set, use findFractionRuleSetRule()
// to find the rule (we should only go into this clause if the
// value is 0)
if (fIsFractionRuleSet) {
return findFractionRuleSetRule(number.asDouble());
return findFractionRuleSetRule((double)number);
}
// if the number is negative, return the negative-number rule
@ -410,7 +413,7 @@ NFRuleSet::findNormalRule(llong number) const
// an explanation of the rollback rule). If we do, roll back
// one rule and return that one instead of the one we'd normally
// return
if (result->shouldRollBack(number.asDouble())) {
if (result->shouldRollBack((double)number)) {
result = rules[hi - 2];
}
return result;
@ -446,17 +449,17 @@ NFRuleSet::findFractionRuleSetRule(double number) const
// and multiply this by the number being formatted. This is
// all the precision we need, and we can do all of the rest
// of the math using integer arithmetic
llong leastCommonMultiple = rules[0]->getBaseValue();
llong numerator;
int64_t leastCommonMultiple = rules[0]->getBaseValue();
int64_t numerator;
{
for (uint32_t i = 1; i < rules.size(); ++i) {
leastCommonMultiple = util_lcm(leastCommonMultiple, rules[i]->getBaseValue());
}
numerator = number * leastCommonMultiple.asDouble() + 0.5;
numerator = util64_fromDouble(number * (double)leastCommonMultiple + 0.5);
}
// for each rule, do the following...
llong tempDifference;
llong difference(uprv_maxMantissa());
int64_t tempDifference;
int64_t difference = util64_fromDouble(uprv_maxMantissa());
int32_t winner = 0;
for (uint32_t i = 0; i < rules.size(); ++i) {
// "numerator" is the numerator of the fraction if the
@ -496,7 +499,7 @@ NFRuleSet::findFractionRuleSetRule(double number) const
// a whole bunch of extra rule sets)
if ((unsigned)(winner + 1) < rules.size() &&
rules[winner + 1]->getBaseValue() == rules[winner]->getBaseValue()) {
double n = rules[winner]->getBaseValue().asDouble() * number;
double n = ((double)rules[winner]->getBaseValue()) * number;
if (n < 0.5 || n >= 2) {
++winner;
}
@ -617,12 +620,14 @@ NFRuleSet::parse(const UnicodeString& text, ParsePosition& pos, double upperBoun
// limit ambiguity by making sure the rules that match a rule's
// are less significant than the rule containing the substitutions)/
{
llong ub(upperBound);
int64_t ub = util64_fromDouble(upperBound);
#ifdef RBNF_DEBUG
{
char ubstr[64];
ub.lltoa(ubstr, 64);
fprintf(stderr, "ub: %g, ll: %s(%x/%x)\n", upperBound, ubstr, ub.hi, ub.lo);
util64_toa(ub, ubstr, 64);
char ubstrhex[64];
util64_toa(ub, ubstrhex, 64, 16);
fprintf(stderr, "ub: %g, i64: %s (%s)\n", upperBound, ubstr, ubstrhex);
}
#endif
for (int32_t i = rules.size(); --i >= 0 && highWaterMark.getIndex() < text.length();) {
@ -682,4 +687,224 @@ NFRuleSet::appendRules(UnicodeString& result) const
}
}
// utility functions
int64_t util64_fromDouble(double d) {
int64_t result = 0;
if (!uprv_isNaN(d)) {
double mant = uprv_maxMantissa();
if (d < -mant) {
d = -mant;
} else if (d > mant) {
d = mant;
}
UBool neg = d < 0;
if (neg) {
d = -d;
}
result = (int64_t)uprv_floor(d);
if (neg) {
result = -result;
}
}
return result;
}
int64_t util64_pow(int32_t r, uint32_t e) {
if (r == 0) {
return 0;
} else if (e == 0) {
return 1;
} else {
int64_t n = r;
while (--e > 0) {
n *= r;
}
return n;
}
}
static const uint8_t asciiDigits[] = {
0x30u, 0x31u, 0x32u, 0x33u, 0x34u, 0x35u, 0x36u, 0x37u,
0x38u, 0x39u, 0x61u, 0x62u, 0x63u, 0x64u, 0x65u, 0x66u,
0x67u, 0x68u, 0x69u, 0x6au, 0x6bu, 0x6cu, 0x6du, 0x6eu,
0x6fu, 0x70u, 0x71u, 0x72u, 0x73u, 0x74u, 0x75u, 0x76u,
0x77u, 0x78u, 0x79u, 0x7au,
};
static const UChar kUMinus = (UChar)0x002d;
static const char kMinus = '-';
static const uint8_t digitInfo[] = {
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0x80u, 0x81u, 0x82u, 0x83u, 0x84u, 0x85u, 0x86u, 0x87u,
0x88u, 0x89u, 0, 0, 0, 0, 0, 0,
0, 0x8au, 0x8bu, 0x8cu, 0x8du, 0x8eu, 0x8fu, 0x90u,
0x91u, 0x92u, 0x93u, 0x94u, 0x95u, 0x96u, 0x97u, 0x98u,
0x99u, 0x9au, 0x9bu, 0x9cu, 0x9du, 0x9eu, 0x9fu, 0xa0u,
0xa1u, 0xa2u, 0xa3u, 0, 0, 0, 0, 0,
0, 0x8au, 0x8bu, 0x8cu, 0x8du, 0x8eu, 0x8fu, 0x90u,
0x91u, 0x92u, 0x93u, 0x94u, 0x95u, 0x96u, 0x97u, 0x98u,
0x99u, 0x9au, 0x9bu, 0x9cu, 0x9du, 0x9eu, 0x9fu, 0xa0u,
0xa1u, 0xa2u, 0xa3u, 0, 0, 0, 0, 0,
};
#ifdef RBNF_DEBUG
int64_t util64_atoi(const char* str, uint32_t radix)
{
if (radix > 36) {
radix = 36;
} else if (radix < 2) {
radix = 2;
}
int64_t lradix = radix;
int neg = 0;
if (*str == kMinus) {
++str;
neg = 1;
}
int64_t result = 0;
uint8_t b;
while ((b = digitInfo[*str++]) && ((b &= 0x7f) < radix)) {
result *= lradix;
result += (int32_t)b;
}
if (neg) {
result = -result;
}
return result;
}
#endif
int64_t util64_utoi(const UChar* str, uint32_t radix)
{
if (radix > 36) {
radix = 36;
} else if (radix < 2) {
radix = 2;
}
int64_t lradix = radix;
int neg = 0;
if (*str == kUMinus) {
++str;
neg = 1;
}
int64_t result = 0;
UChar c;
uint8_t b;
while (((c = *str++) < 0x0080) && (b = digitInfo[c]) && ((b &= 0x7f) < radix)) {
result *= lradix;
result += (int32_t)b;
}
if (neg) {
result = -result;
}
return result;
}
#ifdef RBNF_DEBUG
uint32_t util64_toa(int64_t w, char* buf, uint32_t len, uint32_t radix, UBool raw)
{
if (radix > 36) {
radix = 36;
} else if (radix < 2) {
radix = 2;
}
int64_t base = radix;
char* p = buf;
if (len && (w < 0) && (radix == 10) && !raw) {
w = -w;
*p++ = kMinus;
--len;
} else if (len && (w == 0)) {
*p++ = (char)raw ? 0 : asciiDigits[0];
--len;
}
while (len && w != 0) {
int64_t n = w / base;
int64_t m = n * base;
int32_t d = (int32_t)(w-m);
*p++ = raw ? (char)d : asciiDigits[d];
w = n;
--len;
}
if (len) {
*p = 0; // null terminate if room for caller convenience
}
len = p - buf;
if (*buf == kMinus) {
++buf;
}
while (--p > buf) {
char c = *p;
*p = *buf;
*buf = c;
++buf;
}
return len;
}
#endif
uint32_t util64_tou(int64_t w, UChar* buf, uint32_t len, uint32_t radix, UBool raw)
{
if (radix > 36) {
radix = 36;
} else if (radix < 2) {
radix = 2;
}
int64_t base = radix;
UChar* p = buf;
if (len && (w < 0) && (radix == 10) && !raw) {
w = -w;
*p++ = kUMinus;
--len;
} else if (len && (w == 0)) {
*p++ = (UChar)raw ? 0 : asciiDigits[0];
--len;
}
while (len && (w != 0)) {
int64_t n = w / base;
int64_t m = n * base;
int32_t d = (int32_t)(w-m);
*p++ = (UChar)(raw ? d : asciiDigits[d]);
w = n;
--len;
}
if (len) {
*p = 0; // null terminate if room for caller convenience
}
len = p - buf;
if (*buf == kUMinus) {
++buf;
}
while (--p > buf) {
UChar c = *p;
*p = *buf;
*buf = c;
++buf;
}
return len;
}
U_NAMESPACE_END
/* U_HAVE_RBNF */
#endif

View file

@ -16,12 +16,14 @@
#ifndef NFRS_H
#define NFRS_H
#include "unicode/rbnf.h"
#if U_HAVE_RBNF
#include "unicode/utypes.h"
#include "unicode/umisc.h"
#include "unicode/rbnf.h"
#include "nfrlist.h"
#include "llong.h"
U_NAMESPACE_BEGIN
@ -42,7 +44,7 @@ class NFRuleSet {
void getName(UnicodeString& result) const { result.setTo(name); }
UBool isNamed(const UnicodeString& _name) const { return this->name == _name; }
void format(llong number, UnicodeString& toAppendTo, int32_t pos) const;
void format(int64_t number, UnicodeString& toAppendTo, int32_t pos) const;
void format(double number, UnicodeString& toAppendTo, int32_t pos) const;
UBool parse(const UnicodeString& text, ParsePosition& pos, double upperBound, Formattable& result) const;
@ -50,7 +52,7 @@ class NFRuleSet {
void appendRules(UnicodeString& result) const; // toString
private:
NFRule * findNormalRule(llong number) const;
NFRule * findNormalRule(int64_t number) const;
NFRule * findDoubleRule(double number) const;
NFRule * findFractionRuleSetRule(double number) const;
@ -63,8 +65,28 @@ class NFRuleSet {
UBool fIsPublic;
};
// utilities from old llong.h
// convert mantissa portion of double to int64
int64_t util64_fromDouble(double d);
// raise radix to the power exponent, only non-negative exponents
int64_t util64_pow(int32_t radix, uint32_t exponent);
// convert n to digit string in buffer, return length of string
uint32_t util64_tou(int64_t n, UChar* buffer, uint32_t buflen, uint32_t radix = 10, UBool raw = FALSE);
int64_t util64_utoi(const UChar* str, uint32_t radix = 10);
#ifdef RBNF_DEBUG
uint32_t util64_toa(int64_t n, char* buffer, uint32_t buflen, uint32_t radix = 10, UBool raw = FALSE);
int64_t util64_atoi(const char* str, uint32_t radix);
#endif
U_NAMESPACE_END
/* U_HAVE_RBNF */
#endif
// NFRS_H
#endif

View file

@ -15,6 +15,8 @@
#include "nfrule.h"
#if U_HAVE_RBNF
#include "unicode/rbnf.h"
#include "unicode/tblcoll.h"
#include "unicode/coleitr.h"
@ -124,7 +126,7 @@ NFRule::makeRules(UnicodeString& description,
// base value is an even multiple of its divisor (or it's one
// of the special rules)
if ((rule1->baseValue > 0
&& (rule1->baseValue % ((llong)rule1->radix).pow((int32_t)rule1->exponent)) == 0)
&& (rule1->baseValue % util64_pow(rule1->radix, rule1->exponent)) == 0)
|| rule1->getType() == kImproperFractionRule
|| rule1->getType() == kMasterRule) {
@ -249,7 +251,7 @@ NFRule::parseRuleDescriptor(UnicodeString& description, UErrorCode& status)
// since we don't have Long.parseLong, and this isn't much work anyway,
// just build up the value as we encounter the digits.
else if (descriptor.charAt(0) >= gZero && descriptor.charAt(0) <= gNine) {
llong val = (int32_t)0;
int64_t val = 0;
p = 0;
UChar c = gSpace;
@ -257,7 +259,7 @@ NFRule::parseRuleDescriptor(UnicodeString& description, UErrorCode& status)
// into "tempValue", skip periods, commas, and spaces,
// stop on a slash or > sign (or at the end of the string),
// and throw an exception on any other character
llong ll_10 = (int32_t)10;
int64_t ll_10 = 10;
while (p < descriptor.length()) {
c = descriptor.charAt(p);
if (c >= gZero && c <= gNine) {
@ -284,9 +286,9 @@ NFRule::parseRuleDescriptor(UnicodeString& description, UErrorCode& status)
// in tempValue, skip punctuation, stop on a > mark, and
// throw an exception on anything else
if (c == gSlash) {
val = (int32_t)0;
val = 0;
++p;
llong ll_10 = (int32_t)10;
int64_t ll_10 = 10;
while (p < descriptor.length()) {
c = descriptor.charAt(p);
if (c >= gZero && c <= gNine) {
@ -307,7 +309,7 @@ NFRule::parseRuleDescriptor(UnicodeString& description, UErrorCode& status)
// tempValue now contain's the rule's radix. Set it
// accordingly, and recalculate the rule's exponent
radix = (int16_t)val.asInt();
radix = (int16_t)val;
if (radix == 0) {
// throw new IllegalArgumentException("Rule can't have radix of 0");
status = U_PARSE_ERROR;
@ -442,7 +444,7 @@ NFRule::extractSubstitution(const NFRuleSet* ruleSet,
* @param The new base value for the rule.
*/
void
NFRule::setBaseValue(llong newBaseValue)
NFRule::setBaseValue(int64_t newBaseValue)
{
// set the base value
baseValue = newBaseValue;
@ -493,8 +495,8 @@ NFRule::expectedExponent() const
// we get rounding error in some cases-- for example, log 1000 / log 10
// gives us 1.9999999996 instead of 2. The extra logic here is to take
// that into account
int16_t tempResult = (int16_t)(uprv_log(baseValue.asDouble()) / uprv_log((double)radix));
llong temp = ((llong)radix).pow(tempResult + 1);
int16_t tempResult = (int16_t)(uprv_log((double)baseValue) / uprv_log((double)radix));
int64_t temp = util64_pow(radix, tempResult + 1);
if (temp <= baseValue) {
tempResult += 1;
}
@ -543,39 +545,16 @@ NFRule::operator==(const NFRule& rhs) const
&& *sub2 == *rhs.sub2;
}
/*
static void
util_append_llong(UnicodeString& result, const llong& value)
{
llong n(value);
if (n < 0) {
result.append(gMinus);
n = -n;
}
if (n == 0) {
result.append(gZero);
} else {
llong ll_10((int32_t)10);
while (n != 0) {
llong nn = n / ll_10;
result.append((UChar)(gZero + llong_asInt(n - nn * ll_10)));
n = nn;
}
}
}
*/
/**
* Returns a textual representation of the rule. This won't
* necessarily be the same as the description that this rule
* was created with, but it will produce the same result.
* @return A textual description of the rule
*/
static void util_append64(UnicodeString& result, const llong& n)
static void util_append64(UnicodeString& result, int64_t n)
{
UChar buffer[256];
int32_t len = n.lltou(buffer, sizeof(buffer));
int32_t len = util64_tou(n, buffer, sizeof(buffer));
UnicodeString temp(buffer, len);
result.append(temp);
}
@ -648,7 +627,7 @@ NFRule::appendRuleText(UnicodeString& result) const
* should be inserted
*/
void
NFRule::doFormat(const llong &number, UnicodeString& toInsertInto, int32_t pos) const
NFRule::doFormat(int64_t number, UnicodeString& toInsertInto, int32_t pos) const
{
// first, insert the rule's rule text into toInsertInto at the
// specified position, then insert the results of the substitutions
@ -711,8 +690,8 @@ NFRule::shouldRollBack(double number) const
// of 100, and the value we're trying to format _is_ an even
// multiple of 100. This is called the "rollback rule."
if ((sub1->isModulusSubstitution()) || (sub2->isModulusSubstitution())) {
llong re = ((llong)radix).pow(exponent);
return uprv_fmod(number, re.asDouble()) == 0 && (baseValue % re) != 0;
int64_t re = util64_pow(radix, exponent);
return uprv_fmod(number, (double)re) == 0 && (baseValue % re) != 0;
}
return FALSE;
}
@ -831,7 +810,7 @@ NFRule::doParse(const UnicodeString& text,
int highWaterMark = 0;
double result = 0;
int start = 0;
double tempBaseValue = (baseValue <= 0) ? 0 : baseValue.asDouble();
double tempBaseValue = (double)(baseValue <= 0 ? 0 : baseValue);
UnicodeString temp;
do {
@ -1423,4 +1402,7 @@ NFRule::allIgnorable(const UnicodeString& str) const
U_NAMESPACE_END
/* U_HAVE_RBNF */
#endif

View file

@ -7,11 +7,13 @@
#ifndef NFRULE_H
#define NFRULE_H
#include "unicode/rbnf.h"
#if U_HAVE_RBNF
#include "unicode/utypes.h"
#include "unicode/unistr.h"
#include "llong.h"
U_NAMESPACE_BEGIN
class FieldPosition;
@ -48,15 +50,15 @@ public:
UBool operator==(const NFRule& rhs) const;
UBool operator!=(const NFRule& rhs) const { return !operator==(rhs); }
ERuleType getType() const { return (ERuleType)(baseValue <= 0 ? baseValue.asInt() : kOtherRule); }
ERuleType getType() const { return (ERuleType)(baseValue <= 0 ? baseValue : kOtherRule); }
void setType(ERuleType ruleType) { baseValue = (int32_t)ruleType; }
llong getBaseValue() const { return baseValue; }
void setBaseValue(llong value);
int64_t getBaseValue() const { return baseValue; }
void setBaseValue(int64_t value);
double getDivisor() const { return uprv_pow(radix, exponent); }
void doFormat(const llong &number, UnicodeString& toAppendTo, int32_t pos) const;
void doFormat(int64_t number, UnicodeString& toAppendTo, int32_t pos) const;
void doFormat(double number, UnicodeString& toAppendTo, int32_t pos) const;
UBool doParse(const UnicodeString& text,
@ -87,7 +89,7 @@ private:
int32_t startingAt, int32_t* resultCount) const;
private:
llong baseValue;
int64_t baseValue;
int16_t radix;
int16_t exponent;
UnicodeString ruleText;
@ -98,5 +100,9 @@ private:
U_NAMESPACE_END
/* U_HAVE_RBNF */
#endif
// NFRULE_H
#endif

View file

@ -15,6 +15,8 @@
#include "nfsubs.h"
#if U_HAVE_RBNF
static const UChar gLessThan = 0x003c;
static const UChar gEquals = 0x003d;
static const UChar gGreaterThan = 0x003e;
@ -45,84 +47,84 @@ NFSubstitution::makeSubstitution(int32_t pos,
const UnicodeString& description,
UErrorCode& status)
{
// if the description is empty, return a NullSubstitution
if (description.length() == 0) {
return new NullSubstitution(pos, ruleSet, formatter, description, status);
// if the description is empty, return a NullSubstitution
if (description.length() == 0) {
return new NullSubstitution(pos, ruleSet, formatter, description, status);
}
switch (description.charAt(0)) {
// if the description begins with '<'...
case gLessThan:
// throw an exception if the rule is a negative number
// rule
if (rule->getBaseValue() == NFRule::kNegativeNumberRule) {
// throw new IllegalArgumentException("<< not allowed in negative-number rule");
status = U_PARSE_ERROR;
return NULL;
}
switch (description.charAt(0)) {
// if the description begins with '<'...
case gLessThan:
// throw an exception if the rule is a negative number
// rule
if (rule->getBaseValue() == NFRule::kNegativeNumberRule) {
// throw new IllegalArgumentException("<< not allowed in negative-number rule");
status = U_PARSE_ERROR;
return NULL;
}
// if the rule is a fraction rule, return an
// IntegralPartSubstitution
else if (rule->getBaseValue() == NFRule::kImproperFractionRule
|| rule->getBaseValue() == NFRule::kProperFractionRule
|| rule->getBaseValue() == NFRule::kMasterRule) {
return new IntegralPartSubstitution(pos, ruleSet, formatter, description, status);
}
// if the rule set containing the rule is a fraction
// rule set, return a NumeratorSubstitution
else if (ruleSet->isFractionRuleSet()) {
return new NumeratorSubstitution(pos, rule->getBaseValue().asDouble(),
formatter->getDefaultRuleSet(), formatter, description, status);
}
// otherwise, return a MultiplierSubstitution
else {
return new MultiplierSubstitution(pos, rule->getDivisor(), ruleSet,
formatter, description, status);
}
// if the description begins with '>'...
case gGreaterThan:
// if the rule is a negative-number rule, return
// an AbsoluteValueSubstitution
if (rule->getBaseValue() == NFRule::kNegativeNumberRule) {
return new AbsoluteValueSubstitution(pos, ruleSet, formatter, description, status);
}
// if the rule is a fraction rule, return a
// FractionalPartSubstitution
else if (rule->getBaseValue() == NFRule::kImproperFractionRule
|| rule->getBaseValue() == NFRule::kProperFractionRule
|| rule->getBaseValue() == NFRule::kMasterRule) {
return new FractionalPartSubstitution(pos, ruleSet, formatter, description, status);
}
// if the rule set owning the rule is a fraction rule set,
// throw an exception
else if (ruleSet->isFractionRuleSet()) {
// throw new IllegalArgumentException(">> not allowed in fraction rule set");
status = U_PARSE_ERROR;
return NULL;
}
// otherwise, return a ModulusSubstitution
else {
return new ModulusSubstitution(pos, rule->getDivisor(), predecessor,
ruleSet, formatter, description, status);
}
// if the description begins with '=', always return a
// SameValueSubstitution
case gEquals:
return new SameValueSubstitution(pos, ruleSet, formatter, description, status);
// and if it's anything else, throw an exception
default:
// throw new IllegalArgumentException("Illegal substitution character");
status = U_PARSE_ERROR;
// if the rule is a fraction rule, return an
// IntegralPartSubstitution
else if (rule->getBaseValue() == NFRule::kImproperFractionRule
|| rule->getBaseValue() == NFRule::kProperFractionRule
|| rule->getBaseValue() == NFRule::kMasterRule) {
return new IntegralPartSubstitution(pos, ruleSet, formatter, description, status);
}
return NULL;
// if the rule set containing the rule is a fraction
// rule set, return a NumeratorSubstitution
else if (ruleSet->isFractionRuleSet()) {
return new NumeratorSubstitution(pos, (double)rule->getBaseValue(),
formatter->getDefaultRuleSet(), formatter, description, status);
}
// otherwise, return a MultiplierSubstitution
else {
return new MultiplierSubstitution(pos, rule->getDivisor(), ruleSet,
formatter, description, status);
}
// if the description begins with '>'...
case gGreaterThan:
// if the rule is a negative-number rule, return
// an AbsoluteValueSubstitution
if (rule->getBaseValue() == NFRule::kNegativeNumberRule) {
return new AbsoluteValueSubstitution(pos, ruleSet, formatter, description, status);
}
// if the rule is a fraction rule, return a
// FractionalPartSubstitution
else if (rule->getBaseValue() == NFRule::kImproperFractionRule
|| rule->getBaseValue() == NFRule::kProperFractionRule
|| rule->getBaseValue() == NFRule::kMasterRule) {
return new FractionalPartSubstitution(pos, ruleSet, formatter, description, status);
}
// if the rule set owning the rule is a fraction rule set,
// throw an exception
else if (ruleSet->isFractionRuleSet()) {
// throw new IllegalArgumentException(">> not allowed in fraction rule set");
status = U_PARSE_ERROR;
return NULL;
}
// otherwise, return a ModulusSubstitution
else {
return new ModulusSubstitution(pos, rule->getDivisor(), predecessor,
ruleSet, formatter, description, status);
}
// if the description begins with '=', always return a
// SameValueSubstitution
case gEquals:
return new SameValueSubstitution(pos, ruleSet, formatter, description, status);
// and if it's anything else, throw an exception
default:
// throw new IllegalArgumentException("Illegal substitution character");
status = U_PARSE_ERROR;
}
return NULL;
}
NFSubstitution::NFSubstitution(int32_t _pos,
@ -130,66 +132,66 @@ NFSubstitution::NFSubstitution(int32_t _pos,
const RuleBasedNumberFormat* formatter,
const UnicodeString& description,
UErrorCode& status)
: pos(_pos), ruleSet(NULL), numberFormat(NULL)
: pos(_pos), ruleSet(NULL), numberFormat(NULL)
{
// the description should begin and end with the same character.
// If it doesn't that's a syntax error. Otherwise,
// makeSubstitution() was the only thing that needed to know
// about these characters, so strip them off
UnicodeString workingDescription(description);
if (description.length() >= 2 && description.charAt(0) == description.charAt(
description.length() - 1)) {
workingDescription.remove(description.length() - 1, 1);
workingDescription.remove(0, 1);
}
else if (description.length() != 0) {
// throw new IllegalArgumentException("Illegal substitution syntax");
status = U_PARSE_ERROR;
return;
}
// the description should begin and end with the same character.
// If it doesn't that's a syntax error. Otherwise,
// makeSubstitution() was the only thing that needed to know
// about these characters, so strip them off
UnicodeString workingDescription(description);
if (description.length() >= 2 && description.charAt(0) == description.charAt(
description.length() - 1)) {
workingDescription.remove(description.length() - 1, 1);
workingDescription.remove(0, 1);
}
else if (description.length() != 0) {
// throw new IllegalArgumentException("Illegal substitution syntax");
status = U_PARSE_ERROR;
return;
}
// if the description was just two paired token characters
// (i.e., "<<" or ">>"), it uses the rule set it belongs to to
// format its result
if (workingDescription.length() == 0) {
this->ruleSet = _ruleSet;
}
// if the description contains a rule set name, that's the rule
// set we use to format the result: get a reference to the
// names rule set
else if (workingDescription.charAt(0) == gPercent) {
this->ruleSet = formatter->findRuleSet(workingDescription, status);
}
// if the description begins with 0 or #, treat it as a
// DecimalFormat pattern, and initialize a DecimalFormat with
// that pattern (then set it to use the DecimalFormatSymbols
// belonging to our formatter)
else if (workingDescription.charAt(0) == gPound || workingDescription.charAt(0) ==gZero) {
this->numberFormat = new DecimalFormat(workingDescription, *(formatter->getDecimalFormatSymbols()), status);
// this->numberFormat->setDecimalFormatSymbols(formatter->getDecimalFormatSymbols());
}
// if the description is ">>>", this substitution bypasses the
// usual rule-search process and always uses the rule that precedes
// it in its own rule set's rule list (this is used for place-value
// notations: formats where you want to see a particular part of
// a number even when it's 0)
else if (workingDescription.charAt(0) == gGreaterThan) {
// this causes problems when >>> is used in a frationalPartSubstitution
// this->ruleSet = NULL;
this->ruleSet = _ruleSet;
this->numberFormat = NULL;
}
// and of the description is none of these things, it's a syntax error
else {
// throw new IllegalArgumentException("Illegal substitution syntax");
status = U_PARSE_ERROR;
}
// if the description was just two paired token characters
// (i.e., "<<" or ">>"), it uses the rule set it belongs to to
// format its result
if (workingDescription.length() == 0) {
this->ruleSet = _ruleSet;
}
// if the description contains a rule set name, that's the rule
// set we use to format the result: get a reference to the
// names rule set
else if (workingDescription.charAt(0) == gPercent) {
this->ruleSet = formatter->findRuleSet(workingDescription, status);
}
// if the description begins with 0 or #, treat it as a
// DecimalFormat pattern, and initialize a DecimalFormat with
// that pattern (then set it to use the DecimalFormatSymbols
// belonging to our formatter)
else if (workingDescription.charAt(0) == gPound || workingDescription.charAt(0) ==gZero) {
this->numberFormat = new DecimalFormat(workingDescription, *(formatter->getDecimalFormatSymbols()), status);
// this->numberFormat->setDecimalFormatSymbols(formatter->getDecimalFormatSymbols());
}
// if the description is ">>>", this substitution bypasses the
// usual rule-search process and always uses the rule that precedes
// it in its own rule set's rule list (this is used for place-value
// notations: formats where you want to see a particular part of
// a number even when it's 0)
else if (workingDescription.charAt(0) == gGreaterThan) {
// this causes problems when >>> is used in a frationalPartSubstitution
// this->ruleSet = NULL;
this->ruleSet = _ruleSet;
this->numberFormat = NULL;
}
// and of the description is none of these things, it's a syntax error
else {
// throw new IllegalArgumentException("Illegal substitution syntax");
status = U_PARSE_ERROR;
}
}
NFSubstitution::~NFSubstitution()
{
// cast away const
delete (NumberFormat*)numberFormat; numberFormat = NULL;
// cast away const
delete (NumberFormat*)numberFormat; numberFormat = NULL;
}
/**
@ -201,7 +203,7 @@ NFSubstitution::~NFSubstitution()
*/
void
NFSubstitution::setDivisor(int32_t /*radix*/, int32_t /*exponent*/) {
// a no-op for all substitutions except multiplier and modulus substitutions
// a no-op for all substitutions except multiplier and modulus substitutions
}
@ -213,11 +215,9 @@ const char NFSubstitution::fgClassID = 0;
UClassID
NFSubstitution::getDynamicClassID() const {
return getStaticClassID();
return getStaticClassID();
}
/**
* Compares two substitutions for equality
* @param The substitution to compare this one to
@ -226,16 +226,16 @@ NFSubstitution::getDynamicClassID() const {
UBool
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()
&& pos == rhs.pos
&& (ruleSet == NULL) == (rhs.ruleSet == NULL)
// && ruleSet == rhs.ruleSet causes circularity, other checks to make instead?
&& (numberFormat == NULL
? (rhs.numberFormat == NULL)
: (*numberFormat == *rhs.numberFormat));
// 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()
&& pos == rhs.pos
&& (ruleSet == NULL) == (rhs.ruleSet == NULL)
// && ruleSet == rhs.ruleSet causes circularity, other checks to make instead?
&& (numberFormat == NULL
? (rhs.numberFormat == NULL)
: (*numberFormat == *rhs.numberFormat));
}
/**
@ -247,21 +247,21 @@ NFSubstitution::operator==(const NFSubstitution& rhs) const
void
NFSubstitution::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
text.remove();
text.append(tokenChar());
// 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
text.remove();
text.append(tokenChar());
UnicodeString temp;
if (ruleSet != NULL) {
ruleSet->getName(temp);
} else {
numberFormat->toPattern(temp);
}
text.append(temp);
text.append(tokenChar());
UnicodeString temp;
if (ruleSet != NULL) {
ruleSet->getName(temp);
} else {
numberFormat->toPattern(temp);
}
text.append(temp);
text.append(tokenChar());
}
//-----------------------------------------------------------------------
@ -279,27 +279,27 @@ NFSubstitution::toString(UnicodeString& text) const
* position to determine exactly where to insert the new text)
*/
void
NFSubstitution::doSubstitution(const llong &number, UnicodeString& toInsertInto, int32_t _pos) const
NFSubstitution::doSubstitution(int64_t number, UnicodeString& toInsertInto, int32_t _pos) const
{
if (ruleSet != NULL) {
// perform a transformation on the number that is dependent
// on the type of substitution this is, then just call its
// rule set's format() method to format the result
ruleSet->format(transformNumber(number), toInsertInto, _pos + this->pos);
} else {
// or perform the transformation on the number (preserving
// the result's fractional part if the formatter it set
// to show it), then use that formatter's format() method
// to format the result
double numberToFormat = transformNumber(number.asDouble());
if (numberFormat->getMaximumFractionDigits() == 0) {
numberToFormat = uprv_floor(numberToFormat);
}
UnicodeString temp;
numberFormat->format(numberToFormat, temp);
toInsertInto.insert(_pos + this->pos, temp);
if (ruleSet != NULL) {
// perform a transformation on the number that is dependent
// on the type of substitution this is, then just call its
// rule set's format() method to format the result
ruleSet->format(transformNumber(number), toInsertInto, _pos + this->pos);
} else {
// or perform the transformation on the number (preserving
// the result's fractional part if the formatter it set
// to show it), then use that formatter's format() method
// to format the result
double numberToFormat = transformNumber((double)number);
if (numberFormat->getMaximumFractionDigits() == 0) {
numberToFormat = uprv_floor(numberToFormat);
}
UnicodeString temp;
numberFormat->format(numberToFormat, temp);
toInsertInto.insert(_pos + this->pos, temp);
}
}
/**
@ -314,27 +314,27 @@ NFSubstitution::doSubstitution(const llong &number, UnicodeString& toInsertInto,
*/
void
NFSubstitution::doSubstitution(double number, UnicodeString& toInsertInto, int32_t _pos) const {
// perform a transformation on the number being formatted that
// is dependent on the type of substitution this is
double numberToFormat = transformNumber(number);
// perform a transformation on the number being formatted that
// is dependent on the type of substitution this is
double numberToFormat = transformNumber(number);
// 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) {
ruleSet->format(llong(numberToFormat), toInsertInto, _pos + this->pos);
// 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) {
ruleSet->format(util64_fromDouble(numberToFormat), toInsertInto, _pos + this->pos);
// if the result isn't an integer, then call either our rule set's
// format() method or our DecimalFormat's format() method to
// format the result
// if the result isn't an integer, then call either our rule set's
// format() method or our DecimalFormat's format() method to
// format the result
} else {
if (ruleSet != NULL) {
ruleSet->format(numberToFormat, toInsertInto, _pos + this->pos);
} else {
if (ruleSet != NULL) {
ruleSet->format(numberToFormat, toInsertInto, _pos + this->pos);
} else {
UnicodeString temp;
numberFormat->format(numberToFormat, temp);
toInsertInto.insert(_pos + this->pos, temp);
}
UnicodeString temp;
numberFormat->format(numberToFormat, temp);
toInsertInto.insert(_pos + this->pos, temp);
}
}
}
@ -384,80 +384,79 @@ NFSubstitution::doParse(const UnicodeString& text,
Formattable& result) const
{
#ifdef RBNF_DEBUG
fprintf(stderr, "<nfsubs> %x bv: %g ub: %g\n", this, baseValue, upperBound);
fprintf(stderr, "<nfsubs> %x bv: %g ub: %g\n", this, baseValue, upperBound);
#endif
// figure out the highest base value a rule can have and match
// the text being parsed (this varies according to the type of
// substitutions: multiplier, modulus, and numerator substitutions
// restrict the search to rules with base values lower than their
// own; same-value substitutions leave the upper bound wherever
// it was, and the others allow any rule to match
upperBound = calcUpperBound(upperBound);
// figure out the highest base value a rule can have and match
// the text being parsed (this varies according to the type of
// substitutions: multiplier, modulus, and numerator substitutions
// restrict the search to rules with base values lower than their
// own; same-value substitutions leave the upper bound wherever
// it was, and the others allow any rule to match
upperBound = calcUpperBound(upperBound);
// use our rule set to parse the text. If that fails and
// lenient parsing is enabled (this is always false if the
// formatter's lenient-parsing mode is off, but it may also
// be false even when the formatter's lenient-parse mode is
// on), then also try parsing the text using a default-
// constructed NumberFormat
if (ruleSet != NULL) {
ruleSet->parse(text, parsePosition, upperBound, result);
if (lenientParse && !ruleSet->isFractionRuleSet() && parsePosition.getIndex() == 0) {
UErrorCode status = U_ZERO_ERROR;
NumberFormat* fmt = NumberFormat::createInstance(status);
if (U_SUCCESS(status)) {
fmt->parse(text, result, parsePosition);
}
delete fmt;
}
// ...or use our DecimalFormat to parse the text
} else {
numberFormat->parse(text, result, parsePosition);
// use our rule set to parse the text. If that fails and
// lenient parsing is enabled (this is always false if the
// formatter's lenient-parsing mode is off, but it may also
// be false even when the formatter's lenient-parse mode is
// on), then also try parsing the text using a default-
// constructed NumberFormat
if (ruleSet != NULL) {
ruleSet->parse(text, parsePosition, upperBound, result);
if (lenientParse && !ruleSet->isFractionRuleSet() && parsePosition.getIndex() == 0) {
UErrorCode status = U_ZERO_ERROR;
NumberFormat* fmt = NumberFormat::createInstance(status);
if (U_SUCCESS(status)) {
fmt->parse(text, result, parsePosition);
}
delete fmt;
}
// if the parse was successful, we've already advanced the caller's
// parse position (this is the one function that doesn't have one
// of its own). Derive a parse result and return it as a Long,
// if possible, or a Double
if (parsePosition.getIndex() != 0) {
double tempResult = (result.getType() == Formattable::kLong) ?
(double)result.getLong() :
result.getDouble();
// ...or use our DecimalFormat to parse the text
} else {
numberFormat->parse(text, result, parsePosition);
}
// composeRuleValue() produces a full parse result from
// the partial parse result passed to this function from
// the caller (this is either the owning rule's base value
// or the partial result obtained from composing the
// owning rule's base value with its other substitution's
// parse result) and the partial parse result obtained by
// matching the substitution (which will be the same value
// the caller would get by parsing just this part of the
// text with RuleBasedNumberFormat.parse() ). How the two
// values are used to derive the full parse result depends
// on the types of substitutions: For a regular rule, the
// ultimate result is its multiplier substitution's result
// times the rule's divisor (or the rule's base value) plus
// the modulus substitution's result (which will actually
// supersede part of the rule's base value). For a negative-
// number rule, the result is the negative of its substitution's
// result. For a fraction rule, it's the sum of its two
// substitution results. For a rule in a fraction rule set,
// it's the numerator substitution's result divided by
// the rule's base value. Results from same-value substitutions
// propagate back upard, and null substitutions don't affect
// the result.
tempResult = composeRuleValue(tempResult, baseValue);
result.setDouble(tempResult);
return TRUE;
// if the parse was UNsuccessful, return 0
} else {
result.setLong(0);
return FALSE;
}
// if the parse was successful, we've already advanced the caller's
// parse position (this is the one function that doesn't have one
// of its own). Derive a parse result and return it as a Long,
// if possible, or a Double
if (parsePosition.getIndex() != 0) {
double tempResult = (result.getType() == Formattable::kLong) ?
(double)result.getLong() :
result.getDouble();
// composeRuleValue() produces a full parse result from
// the partial parse result passed to this function from
// the caller (this is either the owning rule's base value
// or the partial result obtained from composing the
// owning rule's base value with its other substitution's
// parse result) and the partial parse result obtained by
// matching the substitution (which will be the same value
// the caller would get by parsing just this part of the
// text with RuleBasedNumberFormat.parse() ). How the two
// values are used to derive the full parse result depends
// on the types of substitutions: For a regular rule, the
// ultimate result is its multiplier substitution's result
// times the rule's divisor (or the rule's base value) plus
// the modulus substitution's result (which will actually
// supersede part of the rule's base value). For a negative-
// number rule, the result is the negative of its substitution's
// result. For a fraction rule, it's the sum of its two
// substitution results. For a rule in a fraction rule set,
// it's the numerator substitution's result divided by
// the rule's base value. Results from same-value substitutions
// propagate back upard, and null substitutions don't affect
// the result.
tempResult = composeRuleValue(tempResult, baseValue);
result.setDouble(tempResult);
return TRUE;
// if the parse was UNsuccessful, return 0
} else {
result.setLong(0);
return FALSE;
}
}
UBool
NFSubstitution::isNullSubstitution() const {
return FALSE;
@ -541,20 +540,20 @@ ModulusSubstitution::ModulusSubstitution(int32_t _pos,
, divisor(_divisor)
, ruleToUse(NULL)
{
ldivisor = _divisor;
ldivisor = util64_fromDouble(_divisor);
// the owning rule's divisor controls the behavior of this
// substitution: rather than keeping a backpointer to the rule,
// we keep a copy of the divisor
// the owning rule's divisor controls the behavior of this
// substitution: rather than keeping a backpointer to the rule,
// we keep a copy of the divisor
if (description == gGreaterGreaterGreaterThan) {
// 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-
// circuits the rule-search process and goes straight to the
// specified rule to format the substitution value
ruleToUse = predecessor;
}
if (description == gGreaterGreaterGreaterThan) {
// 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-
// circuits the rule-search process and goes straight to the
// specified rule to format the substitution value
ruleToUse = predecessor;
}
}
const char ModulusSubstitution::fgClassID = 0;
@ -566,15 +565,16 @@ ModulusSubstitution::getDynamicClassID() const {
UBool ModulusSubstitution::operator==(const NFSubstitution& rhs) const
{
return NFSubstitution::operator==(rhs) &&
divisor == ((const ModulusSubstitution*)&rhs)->divisor &&
ruleToUse == ((const ModulusSubstitution*)&rhs)->ruleToUse;
return NFSubstitution::operator==(rhs) &&
divisor == ((const ModulusSubstitution*)&rhs)->divisor &&
ruleToUse == ((const ModulusSubstitution*)&rhs)->ruleToUse;
}
//-----------------------------------------------------------------------
// formatting
//-----------------------------------------------------------------------
/**
* If this is a &gt;&gt;&gt; substitution, use ruleToUse to fill in
* the substitution. Otherwise, just use the superclass function.
@ -584,20 +584,20 @@ UBool ModulusSubstitution::operator==(const NFSubstitution& rhs) const
* @param pos The position of the rule text in toInsertInto
*/
void
ModulusSubstitution::doSubstitution(const llong & number, UnicodeString& toInsertInto, int32_t _pos) const
ModulusSubstitution::doSubstitution(int64_t number, UnicodeString& toInsertInto, int32_t _pos) const
{
// if this isn't a >>> substitution, just use the inherited version
// of this function (which uses either a rule set or a DecimalFormat
// to format its substitution value)
if (ruleToUse == NULL) {
NFSubstitution::doSubstitution(number, toInsertInto, _pos);
// if this isn't a >>> substitution, just use the inherited version
// of this function (which uses either a rule set or a DecimalFormat
// to format its substitution value)
if (ruleToUse == NULL) {
NFSubstitution::doSubstitution(number, toInsertInto, _pos);
// a >>> substitution goes straight to a particular rule to
// format the substitution value
} else {
llong numberToFormat = transformNumber(number);
ruleToUse->doFormat(numberToFormat, toInsertInto, _pos + getPos());
}
// a >>> substitution goes straight to a particular rule to
// format the substitution value
} else {
int64_t numberToFormat = transformNumber(number);
ruleToUse->doFormat(numberToFormat, toInsertInto, _pos + getPos());
}
}
/**
@ -611,22 +611,21 @@ ModulusSubstitution::doSubstitution(const llong & number, UnicodeString& toIns
void
ModulusSubstitution::doSubstitution(double number, UnicodeString& toInsertInto, int32_t _pos) const
{
// if this isn't a >>> substitution, just use the inherited version
// of this function (which uses either a rule set or a DecimalFormat
// to format its substitution value)
if (ruleToUse == NULL) {
NFSubstitution::doSubstitution(number, toInsertInto, _pos);
// if this isn't a >>> substitution, just use the inherited version
// of this function (which uses either a rule set or a DecimalFormat
// to format its substitution value)
if (ruleToUse == NULL) {
NFSubstitution::doSubstitution(number, toInsertInto, _pos);
// a >>> substitution goes straight to a particular rule to
// format the substitution value
} else {
double numberToFormat = transformNumber(number);
// a >>> substitution goes straight to a particular rule to
// format the substitution value
} else {
double numberToFormat = transformNumber(number);
ruleToUse->doFormat(numberToFormat, toInsertInto, _pos + getPos());
}
ruleToUse->doFormat(numberToFormat, toInsertInto, _pos + getPos());
}
}
//-----------------------------------------------------------------------
// parsing
//-----------------------------------------------------------------------
@ -648,25 +647,25 @@ ModulusSubstitution::doParse(const UnicodeString& text,
UBool lenientParse,
Formattable& result) const
{
// if this isn't a >>> substitution, we can just use the
// inherited parse() routine to do the parsing
if (ruleToUse == NULL) {
return NFSubstitution::doParse(text, parsePosition, baseValue, upperBound, lenientParse, result);
// if this isn't a >>> substitution, we can just use the
// inherited parse() routine to do the parsing
if (ruleToUse == NULL) {
return NFSubstitution::doParse(text, parsePosition, baseValue, upperBound, lenientParse, result);
// but if it IS a >>> substitution, we have to do it here: we
// use the specific rule's doParse() method, and then we have to
// do some of the other work of NFRuleSet.parse()
} else {
ruleToUse->doParse(text, parsePosition, FALSE, upperBound, result);
// but if it IS a >>> substitution, we have to do it here: we
// use the specific rule's doParse() method, and then we have to
// do some of the other work of NFRuleSet.parse()
} else {
ruleToUse->doParse(text, parsePosition, FALSE, upperBound, result);
if (parsePosition.getIndex() != 0) {
double tempResult = result.getDouble();
tempResult = composeRuleValue(tempResult, baseValue);
result.setDouble(tempResult);
}
return TRUE;
if (parsePosition.getIndex() != 0) {
double tempResult = result.getDouble();
tempResult = composeRuleValue(tempResult, baseValue);
result.setDouble(tempResult);
}
return TRUE;
}
}
@ -678,7 +677,7 @@ const char IntegralPartSubstitution::fgClassID = 0;
UClassID
IntegralPartSubstitution::getDynamicClassID() const {
return getStaticClassID();
return getStaticClassID();
}
@ -733,35 +732,35 @@ FractionalPartSubstitution::FractionalPartSubstitution(int32_t _pos,
void
FractionalPartSubstitution::doSubstitution(double number, UnicodeString& toInsertInto, int32_t _pos) const
{
// if we're not in "byDigits" mode, just use the inherited
// doSubstitution() routine
if (!byDigits) {
NFSubstitution::doSubstitution(number, toInsertInto, _pos);
// if we're not in "byDigits" mode, just use the inherited
// doSubstitution() routine
if (!byDigits) {
NFSubstitution::doSubstitution(number, toInsertInto, _pos);
// if we're in "byDigits" mode, transform the value into an integer
// by moving the decimal point eight places to the right and
// pulling digits off the right one at a time, formatting each digit
// as an integer using this substitution's owning rule set
// (this is slower, but more accurate, than doing it from the
// other end)
} else {
int32_t numberToFormat = (int32_t)uprv_round(transformNumber(number) * uprv_pow(10, kMaxDecimalDigits));
// this flag keeps us from formatting trailing zeros. It starts
// out false because we're pulling from the right, and switches
// to true the first time we encounter a non-zero digit
UBool doZeros = FALSE;
for (int32_t i = 0; i < kMaxDecimalDigits; i++) {
int32_t digit = numberToFormat % 10;
if (digit != 0 || doZeros) {
if (doZeros && useSpaces) {
toInsertInto.insert(_pos + getPos(), gSpace);
}
doZeros = TRUE;
getRuleSet()->format(digit, toInsertInto, _pos + getPos());
}
numberToFormat /= 10;
}
// if we're in "byDigits" mode, transform the value into an integer
// by moving the decimal point eight places to the right and
// pulling digits off the right one at a time, formatting each digit
// as an integer using this substitution's owning rule set
// (this is slower, but more accurate, than doing it from the
// other end)
} else {
int32_t numberToFormat = (int32_t)uprv_round(transformNumber(number) * uprv_pow(10, kMaxDecimalDigits));
// this flag keeps us from formatting trailing zeros. It starts
// out false because we're pulling from the right, and switches
// to true the first time we encounter a non-zero digit
UBool doZeros = FALSE;
for (int32_t i = 0; i < kMaxDecimalDigits; i++) {
int64_t digit = numberToFormat % 10;
if (digit != 0 || doZeros) {
if (doZeros && useSpaces) {
toInsertInto.insert(_pos + getPos(), gSpace);
}
doZeros = TRUE;
getRuleSet()->format(digit, toInsertInto, _pos + getPos());
}
numberToFormat /= 10;
}
}
}
//-----------------------------------------------------------------------
@ -784,6 +783,7 @@ FractionalPartSubstitution::doSubstitution(double number, UnicodeString& toInser
* result; otherwise new Long(0). The result is either a Long or
* a Double.
*/
UBool
FractionalPartSubstitution::doParse(const UnicodeString& text,
ParsePosition& parsePosition,
@ -792,70 +792,70 @@ FractionalPartSubstitution::doParse(const UnicodeString& text,
UBool lenientParse,
Formattable& resVal) const
{
// if we're not in byDigits mode, we can just use the inherited
// doParse()
if (!byDigits) {
return NFSubstitution::doParse(text, parsePosition, baseValue, 0, lenientParse, resVal);
// if we're not in byDigits mode, we can just use the inherited
// doParse()
if (!byDigits) {
return NFSubstitution::doParse(text, parsePosition, baseValue, 0, lenientParse, resVal);
// if we ARE in byDigits mode, parse the text one digit at a time
// using this substitution's owning rule set (we do this by setting
// upperBound to 10 when calling doParse() ) until we reach
// nonmatching text
} else {
UnicodeString workText(text);
ParsePosition workPos(1);
double result = 0;
int32_t digit;
double p10 = 0.1;
// if we ARE in byDigits mode, parse the text one digit at a time
// using this substitution's owning rule set (we do this by setting
// upperBound to 10 when calling doParse() ) until we reach
// nonmatching text
} else {
UnicodeString workText(text);
ParsePosition workPos(1);
double result = 0;
int32_t digit;
double p10 = 0.1;
NumberFormat* fmt = NULL;
while (workText.length() > 0 && workPos.getIndex() != 0) {
workPos.setIndex(0);
Formattable temp;
getRuleSet()->parse(workText, workPos, 10, temp);
digit = temp.getType() == Formattable::kLong ?
temp.getLong() :
(int32_t)temp.getDouble();
NumberFormat* fmt = NULL;
while (workText.length() > 0 && workPos.getIndex() != 0) {
workPos.setIndex(0);
Formattable temp;
getRuleSet()->parse(workText, workPos, 10, temp);
digit = temp.getType() == Formattable::kLong ?
temp.getLong() :
(int32_t)temp.getDouble();
if (lenientParse && workPos.getIndex() == 0) {
if (!fmt) {
UErrorCode status = U_ZERO_ERROR;
fmt = NumberFormat::createInstance(status);
if (U_FAILURE(status)) {
delete fmt;
fmt = NULL;
}
}
if (fmt) {
fmt->parse(workText, temp, workPos);
digit = temp.getLong();
}
}
if (lenientParse && workPos.getIndex() == 0) {
if (!fmt) {
UErrorCode status = U_ZERO_ERROR;
fmt = NumberFormat::createInstance(status);
if (U_FAILURE(status)) {
delete fmt;
fmt = NULL;
}
}
if (fmt) {
fmt->parse(workText, temp, workPos);
digit = temp.getLong();
}
}
if (workPos.getIndex() != 0) {
result += digit * p10;
p10 /= 10;
parsePosition.setIndex(parsePosition.getIndex() + workPos.getIndex());
workText.removeBetween(0, workPos.getIndex());
while (workText.length() > 0 && workText.charAt(0) == gSpace) {
workText.removeBetween(0, 1);
parsePosition.setIndex(parsePosition.getIndex() + 1);
}
}
}
delete fmt;
result = composeRuleValue(result, baseValue);
resVal.setDouble(result);
return TRUE;
if (workPos.getIndex() != 0) {
result += digit * p10;
p10 /= 10;
parsePosition.setIndex(parsePosition.getIndex() + workPos.getIndex());
workText.removeBetween(0, workPos.getIndex());
while (workText.length() > 0 && workText.charAt(0) == gSpace) {
workText.removeBetween(0, 1);
parsePosition.setIndex(parsePosition.getIndex() + 1);
}
}
}
delete fmt;
result = composeRuleValue(result, baseValue);
resVal.setDouble(result);
return TRUE;
}
}
UBool
FractionalPartSubstitution::operator==(const NFSubstitution& rhs) const
{
return NFSubstitution::operator==(rhs) &&
((const FractionalPartSubstitution*)&rhs)->byDigits == byDigits;
return NFSubstitution::operator==(rhs) &&
((const FractionalPartSubstitution*)&rhs)->byDigits == byDigits;
}
const char FractionalPartSubstitution::fgClassID = 0;
@ -906,3 +906,6 @@ NullSubstitution::getDynamicClassID() const {
return getStaticClassID();
}
/* U_HAVE_RBNF */
#endif

View file

@ -16,11 +16,12 @@
#ifndef NFSUBS_H
#define NFSUBS_H
#include "nfrule.h"
#if U_HAVE_RBNF
#include "unicode/utypes.h"
#include "unicode/decimfmt.h"
#include "nfrs.h"
#include "nfrule.h"
#include "llong.h"
#include <float.h>
U_NAMESPACE_BEGIN
@ -82,7 +83,7 @@ public:
* rule text begins (this value is added to this substitution's
* position to determine exactly where to insert the new text)
*/
virtual void doSubstitution(const llong &number, UnicodeString& toInsertInto, int32_t pos) const;
virtual void doSubstitution(int64_t number, UnicodeString& toInsertInto, int32_t pos) const;
virtual void doSubstitution(double number, UnicodeString& toInsertInto, int32_t pos) const;
protected:
@ -95,7 +96,7 @@ protected:
* @param The number being formatted
* @return The result of performing the opreration on the number
*/
virtual llong transformNumber(const llong &number) const = 0;
virtual int64_t transformNumber(int64_t number) const = 0;
virtual double transformNumber(double number) const = 0;
public:
@ -211,7 +212,7 @@ public:
const UnicodeString& description,
UErrorCode& status);
llong transformNumber(const llong &number) const { return number; }
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; }
@ -226,7 +227,7 @@ public:
class MultiplierSubstitution : public NFSubstitution {
double divisor;
llong ldivisor;
int64_t ldivisor;
public:
MultiplierSubstitution(int32_t _pos,
@ -237,17 +238,17 @@ public:
UErrorCode& status)
: NFSubstitution(_pos, _ruleSet, formatter, description, status), divisor(_divisor)
{
ldivisor = _divisor;
ldivisor = util64_fromDouble(divisor);
}
void setDivisor(int32_t radix, int32_t exponent) {
divisor = uprv_pow(radix, exponent);
ldivisor = divisor;
ldivisor = util64_fromDouble(divisor);
}
UBool operator==(const NFSubstitution& rhs) const;
llong transformNumber(const llong &number) const {
int64_t transformNumber(int64_t number) const {
return number / ldivisor;
}
@ -272,7 +273,7 @@ public:
class ModulusSubstitution : public NFSubstitution {
double divisor;
llong ldivisor;
int64_t ldivisor;
const NFRule* ruleToUse;
public:
ModulusSubstitution(int32_t pos,
@ -285,15 +286,15 @@ public:
void setDivisor(int32_t radix, int32_t exponent) {
divisor = uprv_pow(radix, exponent);
ldivisor = divisor;
ldivisor = util64_fromDouble(divisor);
}
UBool operator==(const NFSubstitution& rhs) const;
void doSubstitution(const llong &number, UnicodeString& toInsertInto, int32_t pos) const;
void doSubstitution(int64_t number, UnicodeString& toInsertInto, int32_t pos) const;
void doSubstitution(double number, UnicodeString& toInsertInto, int32_t pos) const;
llong transformNumber(const llong &number) const { return number % ldivisor; }
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,
@ -329,7 +330,7 @@ public:
UErrorCode& status)
: NFSubstitution(_pos, _ruleSet, formatter, description, status) {}
llong transformNumber(const llong &number) const { return number; }
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; }
@ -356,8 +357,8 @@ public:
UBool operator==(const NFSubstitution& rhs) const;
void doSubstitution(double number, UnicodeString& toInsertInto, int32_t pos) const;
void doSubstitution(const llong &/*number*/, UnicodeString& /*toInsertInto*/, int32_t /*_pos*/) const {}
llong transformNumber(const llong &/*number*/) const { return llong(0,0); }
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,
@ -387,7 +388,7 @@ public:
UErrorCode& status)
: NFSubstitution(_pos, _ruleSet, formatter, description, status) {}
llong transformNumber(const llong &number) const { return number.abs(); }
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; }
@ -402,7 +403,7 @@ public:
class NumeratorSubstitution : public NFSubstitution {
double denominator;
llong ldenominator;
int64_t ldenominator;
public:
NumeratorSubstitution(int32_t _pos,
double _denominator,
@ -412,12 +413,12 @@ public:
UErrorCode& status)
: NFSubstitution(_pos, _ruleSet, formatter, description, status), denominator(_denominator)
{
ldenominator = _denominator;
ldenominator = util64_fromDouble(denominator);
}
UBool operator==(const NFSubstitution& rhs) const;
llong transformNumber(const llong &number) const { return number * ldenominator; }
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,
@ -454,8 +455,8 @@ public:
void toString(UnicodeString& /*result*/) const {}
void doSubstitution(double /*number*/, UnicodeString& /*toInsertInto*/, int32_t /*_pos*/) const {}
void doSubstitution(const llong &/*number*/, UnicodeString& /*toInsertInto*/, int32_t /*_pos*/) const {}
llong transformNumber(const llong &/*number*/) const { return llong(0,0); }
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*/,
@ -478,5 +479,8 @@ public:
U_NAMESPACE_END
/* U_HAVE_RBNF */
#endif
// NFSUBS_H
#endif

View file

@ -6,6 +6,8 @@
#include "unicode/rbnf.h"
#if U_HAVE_RBNF
#include "nfrs.h"
#include "cmemory.h"
@ -219,20 +221,20 @@ RuleBasedNumberFormat::format(int32_t number,
UnicodeString& toAppendTo,
FieldPosition& pos) const
{
defaultRuleSet->format(llong(number), toAppendTo, toAppendTo.length());
defaultRuleSet->format((int64_t)number, toAppendTo, toAppendTo.length());
return toAppendTo;
}
#if 0
UnicodeString&
RuleBasedNumberFormat::format(llong number,
RuleBasedNumberFormat::format(int64_t number,
UnicodeString& toAppendTo,
FieldPosition& pos) const
{
defaultRuleSet->format(number, toAppendTo, toAppendTo.length());
return toAppendTo;
}
#endif
UnicodeString&
RuleBasedNumberFormat::format(double number,
@ -251,7 +253,7 @@ RuleBasedNumberFormat::format(int32_t number,
FieldPosition& pos,
UErrorCode& status) const
{
// return format(llong(number), ruleSetName, toAppendTo, pos, status);
// return format((int64_t)number, ruleSetName, toAppendTo, pos, status);
if (U_SUCCESS(status)) {
if (ruleSetName.indexOf(gPercentPercent) == 0) {
// throw new IllegalArgumentException("Can't use internal rule set");
@ -259,16 +261,16 @@ RuleBasedNumberFormat::format(int32_t number,
} else {
NFRuleSet *rs = findRuleSet(ruleSetName, status);
if (rs) {
rs->format(llong(number), toAppendTo, toAppendTo.length());
rs->format((int64_t)number, toAppendTo, toAppendTo.length());
}
}
}
return toAppendTo;
}
#if 0
UnicodeString&
RuleBasedNumberFormat::format(llong number,
RuleBasedNumberFormat::format(int64_t number,
const UnicodeString& ruleSetName,
UnicodeString& toAppendTo,
FieldPosition& pos,
@ -287,7 +289,7 @@ RuleBasedNumberFormat::format(llong number,
}
return toAppendTo;
}
#endif
// make linker happy
UnicodeString&
@ -630,3 +632,5 @@ RuleBasedNumberFormat::getDecimalFormatSymbols() const
return decimalFormatSymbols;
}
/* U_HAVE_RBNF */
#endif

View file

@ -7,6 +7,11 @@
#ifndef RBNF_H
#define RBNF_H
#if 0 //U_INT64_T_UNAVAILABLE -- fix once George defines this
#define U_HAVE_RBNF 0
#else
#define U_HAVE_RBNF 1
#include "unicode/coll.h"
#include "unicode/dcfmtsym.h"
#include "unicode/fmtable.h"
@ -583,7 +588,7 @@ public:
virtual int32_t getNumberOfRuleSetNames() const;
/**
* Formats the specified number using the default ruleset.
* Formats the specified 32-bit number using the default ruleset.
* @param number The number to format.
* @param toAppendTo the string that will hold the (appended) result
* @param pos the fieldposition
@ -593,6 +598,18 @@ public:
virtual UnicodeString& format(int32_t number,
UnicodeString& toAppendTo,
FieldPosition& pos) const;
/**
* Formats the specified 64-bit number using the default ruleset.
* @param number The number to format.
* @param toAppendTo the string that will hold the (appended) result
* @param pos the fieldposition
* @return A textual representation of the number.
* @draft ICU 2.1
*/
virtual UnicodeString& format(int64_t number,
UnicodeString& toAppendTo,
FieldPosition& pos) const;
/**
* Formats the specified number using the default ruleset.
* @param number The number to format.
@ -621,6 +638,22 @@ public:
UnicodeString& toAppendTo,
FieldPosition& pos,
UErrorCode& status) const;
/**
* Formats the specified 64-bit number using the default ruleset.
* @param number The number to format.
* @param ruleSetName The name of the rule set to format the number with.
* This must be the name of a valid public rule set for this formatter.
* @param toAppendTo the string that will hold the (appended) result
* @param pos the fieldposition
* @param status the status
* @return A textual representation of the number.
* @draft ICU 2.1
*/
virtual UnicodeString& format(int64_t number,
const UnicodeString& ruleSetName,
UnicodeString& toAppendTo,
FieldPosition& pos,
UErrorCode& status) const;
/**
* Formats the specified number using the default ruleset.
* @param number The number to format.
@ -824,5 +857,8 @@ RuleBasedNumberFormat::getDefaultRuleSet() const {
U_NAMESPACE_END
/* U_HAVE_RBNF */
#endif
/* RBNF_H */
#endif

View file

@ -137,8 +137,11 @@ unum_open( UNumberFormatStyle style,
break;
case UNUM_SPELLOUT:
#if U_HAVE_RBNF
return (UNumberFormat*)new RuleBasedNumberFormat(URBNF_SPELLOUT, Locale(locale), *status);
#else
// fall through
#endif
default:
*status = U_UNSUPPORTED_ERROR;
return 0;

View file

@ -6,11 +6,13 @@
*/
#include "itrbnf.h"
#include "unicode/umachine.h"
#include "unicode/tblcoll.h"
#include "unicode/coleitr.h"
#include "unicode/ures.h"
#include "unicode/ustring.h"
#include "llong.h"
//#include "llong.h"
#include <string.h>
@ -35,6 +37,7 @@ void IntlTestRBNF::runIndexedTest(int32_t index, UBool exec, const char* &name,
{
if (exec) logln("TestSuite RuleBasedNumberFormat");
switch (index) {
#if U_HAVE_RBNF
TESTCASE(0, TestEnglishSpellout);
TESTCASE(1, TestOrdinalAbbreviations);
TESTCASE(2, TestDurations);
@ -46,13 +49,18 @@ void IntlTestRBNF::runIndexedTest(int32_t index, UBool exec, const char* &name,
TESTCASE(8, TestThaiSpellout);
TESTCASE(9, TestAPI);
TESTCASE(10, TestFractionalRuleSet);
TESTCASE(11, TestLLong);
// TESTCASE(11, TestLLong);
#else
TESTCASE(0, TestRBNFDisabled);
#endif
default:
name = "";
break;
}
}
#if U_HAVE_RBNF
void
IntlTestRBNF::TestAPI() {
// This test goes through the APIs that were not tested before.
@ -265,6 +273,7 @@ void IntlTestRBNF::TestFractionalRuleSet()
}
}
#if 0
#define LLAssert(a) \
if (!(a)) errln("FAIL: " #a)
@ -890,6 +899,9 @@ void IntlTestRBNF::TestLLong()
}
}
/* if 0 */
#endif
void
IntlTestRBNF::TestEnglishSpellout()
{
@ -1389,3 +1401,13 @@ IntlTestRBNF::doLenientParseTest(RuleBasedNumberFormat* formatter, const char* t
}
}
/* U_HAVE_RBNF */
#else
void
IntlTestRBNF::TestRBNFDisabled() {
logln("*** RBNF currently disabled on this platform ***");
}
/* U_HAVE_RBNF */
#endif

View file

@ -20,6 +20,7 @@ class IntlTestRBNF : public IntlTest {
// IntlTest override
virtual void runIndexedTest(int32_t index, UBool exec, const char* &name, char* par);
#if U_HAVE_RBNF
/**
* Perform an API test
*/
@ -30,12 +31,14 @@ class IntlTestRBNF : public IntlTest {
*/
virtual void TestFractionalRuleSet();
#if 0
/**
* Perform API tests on llong
*/
virtual void TestLLong();
virtual void TestLLongConstructors();
virtual void TestLLongSimpleOperators();
#endif
/**
* Perform a simple spot check on the English spellout rules
@ -85,6 +88,14 @@ class IntlTestRBNF : public IntlTest {
protected:
virtual void doTest(RuleBasedNumberFormat* formatter, const char* testData[][2], UBool testParsing);
virtual void doLenientParseTest(RuleBasedNumberFormat* formatter, const char* testData[][2]);
/* U_HAVE_RBNF */
#else
virtual void TestRBNFDisabled();
/* U_HAVE_RBNF */
#endif
};
// endif ITRBNF_H

View file

@ -25,6 +25,7 @@ void RbnfRoundTripTest::runIndexedTest(int32_t index, UBool exec, const char* &n
{
if (exec) logln("TestSuite RuleBasedNumberFormatRT");
switch (index) {
#if U_HAVE_RBNF
TESTCASE(0, TestEnglishSpelloutRT);
TESTCASE(1, TestDurationsRT);
TESTCASE(2, TestSpanishSpelloutRT);
@ -37,12 +38,17 @@ void RbnfRoundTripTest::runIndexedTest(int32_t index, UBool exec, const char* &n
TESTCASE(9, TestJapaneseSpelloutRT);
TESTCASE(10, TestRussianSpelloutRT);
TESTCASE(11, TestGreekSpelloutRT);
#else
TESTCASE(0, TestRBNFDisabled);
#endif
default:
name = "";
break;
}
}
#if U_HAVE_RBNF
/**
* Perform an exhaustive round-trip test on the English spellout rules
*/
@ -339,3 +345,13 @@ RbnfRoundTripTest::doTest(const RuleBasedNumberFormat* formatter,
}
}
/* U_HAVE_RBNF */
#else
void
RbnfRoundTripTest::TestRBNFDisabled() {
logln("*** RBNF currently disabled on this platform ***");
}
/* U_HAVE_RBNF */
#endif

View file

@ -18,6 +18,7 @@ class RbnfRoundTripTest : public IntlTest {
// IntlTest override
virtual void runIndexedTest(int32_t index, UBool exec, const char* &name, char* par);
#if U_HAVE_RBNF
/**
* Perform an exhaustive round-trip test on the English spellout rules
*/
@ -80,6 +81,14 @@ class RbnfRoundTripTest : public IntlTest {
protected:
void doTest(const RuleBasedNumberFormat* formatter, double lowLimit, double highLimit);
/* U_HAVE_RBNF */
#else
void TestRBNFDisabled();
/* U_HAVE_RBNF */
#endif
};
// endif ITRBNFRT_H