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