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