Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(145)

Side by Side Diff: icu46/source/i18n/nfsubs.cpp

Issue 5516007: Check in the pristine copy of ICU 4.6... (Closed) Base URL: svn://chrome-svn/chrome/trunk/deps/third_party/
Patch Set: Created 10 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « icu46/source/i18n/nfsubs.h ('k') | icu46/source/i18n/nortrans.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Property Changes:
Added: svn:eol-style
+ LF
OLDNEW
(Empty)
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 oldUpperB ound; }
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), diviso r(_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 divis or; }
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, int 32_t pos) const;
146 virtual void doSubstitution(double number, UnicodeString& toInsertInto, int3 2_t pos) const;
147
148 virtual int64_t transformNumber(int64_t number) const { return number % ldiv isor; }
149 virtual double transformNumber(double number) const { return uprv_fmod(numbe r, 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) co nst {
159 return oldRuleValue - uprv_fmod(oldRuleValue, divisor) + newRuleValue;
160 }
161
162 virtual double calcUpperBound(double /*oldUpperBound*/) const { return divis or; }
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(numb er); }
184 virtual double composeRuleValue(double newRuleValue, double oldRuleValue) co nst { return newRuleValue + oldRuleValue; }
185 virtual double calcUpperBound(double /*oldUpperBound*/) const { return DBL_M AX; }
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, int3 2_t pos) const;
207 virtual void doSubstitution(int64_t /*number*/, UnicodeString& /*toInsertInt o*/, 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_f loor(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) co nst { 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(numbe r); }
238 virtual double composeRuleValue(double newRuleValue, double /*oldRuleValue*/ ) const { return -newRuleValue; }
239 virtual double calcUpperBound(double /*oldUpperBound*/) const { return DBL_M AX; }
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 * lden ominator; }
274 virtual double transformNumber(double number) const { return uprv_round(numb er * denominator); }
275
276 virtual void doSubstitution(int64_t /*number*/, UnicodeString& /*toInsertInt o*/, int32_t /*_pos*/) const {}
277 virtual void doSubstitution(double number, UnicodeString& toInsertInto, int3 2_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) co nst { return newRuleValue / oldRuleValue; }
286 virtual double calcUpperBound(double /*oldUpperBound*/) const { return denom inator; }
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& /*toInsertInt o*/, 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 /*oldRuleVal ue*/) 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 calle d
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-nu mber 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, descrip tion, 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, descri ption, 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, descr iption, 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 ru le 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, s tatus);
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->getDecimalForm atSymbols());
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, int3 2_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
618 // if the result is an integer, from here on out we work in integer
619 // space (saving time and memory and preserving accuracy)
620 if (numberToFormat == uprv_floor(numberToFormat) && ruleSet != NULL) {
621 ruleSet->format(util64_fromDouble(numberToFormat), toInsertInto, _pos + this->pos);
622
623 // if the result isn't an integer, then call either our rule set's
624 // format() method or our DecimalFormat's format() method to
625 // format the result
626 } else {
627 if (ruleSet != NULL) {
628 ruleSet->format(numberToFormat, toInsertInto, _pos + this->pos);
629 } else if (numberFormat != NULL) {
630 UnicodeString temp;
631 numberFormat->format(numberToFormat, temp);
632 toInsertInto.insert(_pos + this->pos, temp);
633 }
634 }
635 }
636
637
638 //-----------------------------------------------------------------------
639 // parsing
640 //-----------------------------------------------------------------------
641
642 #ifdef RBNF_DEBUG
643 #include <stdio.h>
644 #endif
645
646 /**
647 * Parses a string using the rule set or DecimalFormat belonging
648 * to this substitution. If there's a match, a mathematical
649 * operation (the inverse of the one used in formatting) is
650 * performed on the result of the parse and the value passed in
651 * and returned as the result. The parse position is updated to
652 * point to the first unmatched character in the string.
653 * @param text The string to parse
654 * @param parsePosition On entry, ignored, but assumed to be 0.
655 * On exit, this is updated to point to the first unmatched
656 * character (or 0 if the substitution didn't match)
657 * @param baseValue A partial parse result that should be
658 * combined with the result of this parse
659 * @param upperBound When searching the rule set for a rule
660 * matching the string passed in, only rules with base values
661 * lower than this are considered
662 * @param lenientParse If true and matching against rules fails,
663 * the substitution will also try matching the text against
664 * numerals using a default-costructed NumberFormat. If false,
665 * no extra work is done. (This value is false whenever the
666 * formatter isn't in lenient-parse mode, but is also false
667 * under some conditions even when the formatter _is_ in
668 * lenient-parse mode.)
669 * @return If there's a match, this is the result of composing
670 * baseValue with whatever was returned from matching the
671 * characters. This will be either a Long or a Double. If there's
672 * no match this is new Long(0) (not null), and parsePosition
673 * is left unchanged.
674 */
675 UBool
676 NFSubstitution::doParse(const UnicodeString& text,
677 ParsePosition& parsePosition,
678 double baseValue,
679 double upperBound,
680 UBool lenientParse,
681 Formattable& result) const
682 {
683 #ifdef RBNF_DEBUG
684 fprintf(stderr, "<nfsubs> %x bv: %g ub: %g\n", this, baseValue, upperBound);
685 #endif
686 // figure out the highest base value a rule can have and match
687 // the text being parsed (this varies according to the type of
688 // substitutions: multiplier, modulus, and numerator substitutions
689 // restrict the search to rules with base values lower than their
690 // own; same-value substitutions leave the upper bound wherever
691 // it was, and the others allow any rule to match
692 upperBound = calcUpperBound(upperBound);
693
694 // use our rule set to parse the text. If that fails and
695 // lenient parsing is enabled (this is always false if the
696 // formatter's lenient-parsing mode is off, but it may also
697 // be false even when the formatter's lenient-parse mode is
698 // on), then also try parsing the text using a default-
699 // constructed NumberFormat
700 if (ruleSet != NULL) {
701 ruleSet->parse(text, parsePosition, upperBound, result);
702 if (lenientParse && !ruleSet->isFractionRuleSet() && parsePosition.getIn dex() == 0) {
703 UErrorCode status = U_ZERO_ERROR;
704 NumberFormat* fmt = NumberFormat::createInstance(status);
705 if (U_SUCCESS(status)) {
706 fmt->parse(text, result, parsePosition);
707 }
708 delete fmt;
709 }
710
711 // ...or use our DecimalFormat to parse the text
712 } else if (numberFormat != NULL) {
713 numberFormat->parse(text, result, parsePosition);
714 }
715
716 // if the parse was successful, we've already advanced the caller's
717 // parse position (this is the one function that doesn't have one
718 // of its own). Derive a parse result and return it as a Long,
719 // if possible, or a Double
720 if (parsePosition.getIndex() != 0) {
721 UErrorCode status = U_ZERO_ERROR;
722 double tempResult = result.getDouble(status);
723
724 // composeRuleValue() produces a full parse result from
725 // the partial parse result passed to this function from
726 // the caller (this is either the owning rule's base value
727 // or the partial result obtained from composing the
728 // owning rule's base value with its other substitution's
729 // parse result) and the partial parse result obtained by
730 // matching the substitution (which will be the same value
731 // the caller would get by parsing just this part of the
732 // text with RuleBasedNumberFormat.parse() ). How the two
733 // values are used to derive the full parse result depends
734 // on the types of substitutions: For a regular rule, the
735 // ultimate result is its multiplier substitution's result
736 // times the rule's divisor (or the rule's base value) plus
737 // the modulus substitution's result (which will actually
738 // supersede part of the rule's base value). For a negative-
739 // number rule, the result is the negative of its substitution's
740 // result. For a fraction rule, it's the sum of its two
741 // substitution results. For a rule in a fraction rule set,
742 // it's the numerator substitution's result divided by
743 // the rule's base value. Results from same-value substitutions
744 // propagate back upard, and null substitutions don't affect
745 // the result.
746 tempResult = composeRuleValue(tempResult, baseValue);
747 result.setDouble(tempResult);
748 return TRUE;
749 // if the parse was UNsuccessful, return 0
750 } else {
751 result.setLong(0);
752 return FALSE;
753 }
754 }
755
756 UBool
757 NFSubstitution::isNullSubstitution() const {
758 return FALSE;
759 }
760
761 /**
762 * Returns true if this is a modulus substitution. (We didn't do this
763 * with instanceof partially because it causes source files to
764 * proliferate and partially because we have to port this to C++.)
765 * @return true if this object is an instance of ModulusSubstitution
766 */
767 UBool
768 NFSubstitution::isModulusSubstitution() const {
769 return FALSE;
770 }
771
772 //===================================================================
773 // SameValueSubstitution
774 //===================================================================
775
776 /**
777 * A substitution that passes the value passed to it through unchanged.
778 * Represented by == in rule descriptions.
779 */
780 SameValueSubstitution::SameValueSubstitution(int32_t _pos,
781 const NFRuleSet* _ruleSet,
782 const RuleBasedNumberFormat* formatter,
783 const UnicodeString& description,
784 UErrorCode& status)
785 : NFSubstitution(_pos, _ruleSet, formatter, description, status)
786 {
787 if (description == gEqualsEquals) {
788 // throw new IllegalArgumentException("== is not a legal token");
789 status = U_PARSE_ERROR;
790 }
791 }
792
793 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(SameValueSubstitution)
794
795 //===================================================================
796 // MultiplierSubstitution
797 //===================================================================
798
799 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(MultiplierSubstitution)
800
801 UBool MultiplierSubstitution::operator==(const NFSubstitution& rhs) const
802 {
803 return NFSubstitution::operator==(rhs) &&
804 divisor == ((const MultiplierSubstitution*)&rhs)->divisor;
805 }
806
807
808 //===================================================================
809 // ModulusSubstitution
810 //===================================================================
811
812 /**
813 * A substitution that divides the number being formatted by the its rule's
814 * divisor and formats the remainder. Represented by "&gt;&gt;" in a
815 * regular rule.
816 */
817 ModulusSubstitution::ModulusSubstitution(int32_t _pos,
818 double _divisor,
819 const NFRule* predecessor,
820 const NFRuleSet* _ruleSet,
821 const RuleBasedNumberFormat* formatter,
822 const UnicodeString& description,
823 UErrorCode& status)
824 : NFSubstitution(_pos, _ruleSet, formatter, description, status)
825 , divisor(_divisor)
826 , ruleToUse(NULL)
827 {
828 ldivisor = util64_fromDouble(_divisor);
829
830 // the owning rule's divisor controls the behavior of this
831 // substitution: rather than keeping a backpointer to the rule,
832 // we keep a copy of the divisor
833
834 if (ldivisor == 0) {
835 status = U_PARSE_ERROR;
836 }
837
838 if (description == gGreaterGreaterGreaterThan) {
839 // the >>> token doesn't alter how this substituion calculates the
840 // values it uses for formatting and parsing, but it changes
841 // what's done with that value after it's obtained: >>> short-
842 // circuits the rule-search process and goes straight to the
843 // specified rule to format the substitution value
844 ruleToUse = predecessor;
845 }
846 }
847
848 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(ModulusSubstitution)
849
850 UBool ModulusSubstitution::operator==(const NFSubstitution& rhs) const
851 {
852 return NFSubstitution::operator==(rhs) &&
853 divisor == ((const ModulusSubstitution*)&rhs)->divisor &&
854 ruleToUse == ((const ModulusSubstitution*)&rhs)->ruleToUse;
855 }
856
857 //-----------------------------------------------------------------------
858 // formatting
859 //-----------------------------------------------------------------------
860
861
862 /**
863 * If this is a &gt;&gt;&gt; substitution, use ruleToUse to fill in
864 * the substitution. Otherwise, just use the superclass function.
865 * @param number The number being formatted
866 * @toInsertInto The string to insert the result of this substitution
867 * into
868 * @param pos The position of the rule text in toInsertInto
869 */
870 void
871 ModulusSubstitution::doSubstitution(int64_t number, UnicodeString& toInsertInto, int32_t _pos) const
872 {
873 // if this isn't a >>> substitution, just use the inherited version
874 // of this function (which uses either a rule set or a DecimalFormat
875 // to format its substitution value)
876 if (ruleToUse == NULL) {
877 NFSubstitution::doSubstitution(number, toInsertInto, _pos);
878
879 // a >>> substitution goes straight to a particular rule to
880 // format the substitution value
881 } else {
882 int64_t numberToFormat = transformNumber(number);
883 ruleToUse->doFormat(numberToFormat, toInsertInto, _pos + getPos());
884 }
885 }
886
887 /**
888 * If this is a &gt;&gt;&gt; substitution, use ruleToUse to fill in
889 * the substitution. Otherwise, just use the superclass function.
890 * @param number The number being formatted
891 * @toInsertInto The string to insert the result of this substitution
892 * into
893 * @param pos The position of the rule text in toInsertInto
894 */
895 void
896 ModulusSubstitution::doSubstitution(double number, UnicodeString& toInsertInto, int32_t _pos) const
897 {
898 // if this isn't a >>> substitution, just use the inherited version
899 // of this function (which uses either a rule set or a DecimalFormat
900 // to format its substitution value)
901 if (ruleToUse == NULL) {
902 NFSubstitution::doSubstitution(number, toInsertInto, _pos);
903
904 // a >>> substitution goes straight to a particular rule to
905 // format the substitution value
906 } else {
907 double numberToFormat = transformNumber(number);
908
909 ruleToUse->doFormat(numberToFormat, toInsertInto, _pos + getPos());
910 }
911 }
912
913 //-----------------------------------------------------------------------
914 // parsing
915 //-----------------------------------------------------------------------
916
917 /**
918 * If this is a &gt;&gt;&gt; substitution, match only against ruleToUse.
919 * Otherwise, use the superclass function.
920 * @param text The string to parse
921 * @param parsePosition Ignored on entry, updated on exit to point to
922 * the first unmatched character.
923 * @param baseValue The partial parse result prior to calling this
924 * routine.
925 */
926 UBool
927 ModulusSubstitution::doParse(const UnicodeString& text,
928 ParsePosition& parsePosition,
929 double baseValue,
930 double upperBound,
931 UBool lenientParse,
932 Formattable& result) const
933 {
934 // if this isn't a >>> substitution, we can just use the
935 // inherited parse() routine to do the parsing
936 if (ruleToUse == NULL) {
937 return NFSubstitution::doParse(text, parsePosition, baseValue, upperBoun d, lenientParse, result);
938
939 // but if it IS a >>> substitution, we have to do it here: we
940 // use the specific rule's doParse() method, and then we have to
941 // do some of the other work of NFRuleSet.parse()
942 } else {
943 ruleToUse->doParse(text, parsePosition, FALSE, upperBound, result);
944
945 if (parsePosition.getIndex() != 0) {
946 UErrorCode status = U_ZERO_ERROR;
947 double tempResult = result.getDouble(status);
948 tempResult = composeRuleValue(tempResult, baseValue);
949 result.setDouble(tempResult);
950 }
951
952 return TRUE;
953 }
954 }
955
956
957 //===================================================================
958 // IntegralPartSubstitution
959 //===================================================================
960
961 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(IntegralPartSubstitution)
962
963
964 //===================================================================
965 // FractionalPartSubstitution
966 //===================================================================
967
968
969 /**
970 * Constructs a FractionalPartSubstitution. This object keeps a flag
971 * telling whether it should format by digits or not. In addition,
972 * it marks the rule set it calls (if any) as a fraction rule set.
973 */
974 FractionalPartSubstitution::FractionalPartSubstitution(int32_t _pos,
975 const NFRuleSet* _ruleSet,
976 const RuleBasedNumberFormat* formatter,
977 const UnicodeString& description,
978 UErrorCode& status)
979 : NFSubstitution(_pos, _ruleSet, formatter, description, status)
980 , byDigits(FALSE)
981 , useSpaces(TRUE)
982
983 {
984 // akk, ruleSet can change in superclass constructor
985 if (description == gGreaterGreaterThan ||
986 description == gGreaterGreaterGreaterThan ||
987 _ruleSet == getRuleSet()) {
988 byDigits = TRUE;
989 if (description == gGreaterGreaterGreaterThan) {
990 useSpaces = FALSE;
991 }
992 } else {
993 // cast away const
994 ((NFRuleSet*)getRuleSet())->makeIntoFractionRuleSet();
995 }
996 }
997
998 //-----------------------------------------------------------------------
999 // formatting
1000 //-----------------------------------------------------------------------
1001
1002 /**
1003 * If in "by digits" mode, fills in the substitution one decimal digit
1004 * at a time using the rule set containing this substitution.
1005 * Otherwise, uses the superclass function.
1006 * @param number The number being formatted
1007 * @param toInsertInto The string to insert the result of formatting
1008 * the substitution into
1009 * @param pos The position of the owning rule's rule text in
1010 * toInsertInto
1011 */
1012 void
1013 FractionalPartSubstitution::doSubstitution(double number, UnicodeString& toInser tInto, int32_t _pos) const
1014 {
1015 // if we're not in "byDigits" mode, just use the inherited
1016 // doSubstitution() routine
1017 if (!byDigits) {
1018 NFSubstitution::doSubstitution(number, toInsertInto, _pos);
1019
1020 // if we're in "byDigits" mode, transform the value into an integer
1021 // by moving the decimal point eight places to the right and
1022 // pulling digits off the right one at a time, formatting each digit
1023 // as an integer using this substitution's owning rule set
1024 // (this is slower, but more accurate, than doing it from the
1025 // other end)
1026 } else {
1027 // int32_t numberToFormat = (int32_t)uprv_round(transformNumber(num ber) * uprv_pow(10, kMaxDecimalDigits));
1028 // // this flag keeps us from formatting trailing zeros. It starts
1029 // // out false because we're pulling from the right, and switches
1030 // // to true the first time we encounter a non-zero digit
1031 // UBool doZeros = FALSE;
1032 // for (int32_t i = 0; i < kMaxDecimalDigits; i++) {
1033 // int64_t digit = numberToFormat % 10;
1034 // if (digit != 0 || doZeros) {
1035 // if (doZeros && useSpaces) {
1036 // toInsertInto.insert(_pos + getPos(), gSpace);
1037 // }
1038 // doZeros = TRUE;
1039 // getRuleSet()->format(digit, toInsertInto, _pos + getPos( ));
1040 // }
1041 // numberToFormat /= 10;
1042 // }
1043
1044 DigitList dl;
1045 dl.set(number);
1046 dl.roundFixedPoint(20); // round to 20 fraction digits.
1047 dl.reduce(); // Removes any trailing zeros.
1048
1049 UBool pad = FALSE;
1050 for (int32_t didx = dl.getCount()-1; didx>=dl.getDecimalAt(); didx--) {
1051 // Loop iterates over fraction digits, starting with the LSD.
1052 // include both real digits from the number, and zeros
1053 // to the left of the MSD but to the right of the decimal point.
1054 if (pad && useSpaces) {
1055 toInsertInto.insert(_pos + getPos(), gSpace);
1056 } else {
1057 pad = TRUE;
1058 }
1059 int64_t digit = didx>=0 ? dl.getDigit(didx) - '0' : 0;
1060 getRuleSet()->format(digit, toInsertInto, _pos + getPos());
1061 }
1062
1063 if (!pad) {
1064 // hack around lack of precision in digitlist. if we would end up with
1065 // "foo point" make sure we add a " zero" to the end.
1066 getRuleSet()->format((int64_t)0, toInsertInto, _pos + getPos());
1067 }
1068 }
1069 }
1070
1071 //-----------------------------------------------------------------------
1072 // parsing
1073 //-----------------------------------------------------------------------
1074
1075 /**
1076 * If in "by digits" mode, parses the string as if it were a string
1077 * of individual digits; otherwise, uses the superclass function.
1078 * @param text The string to parse
1079 * @param parsePosition Ignored on entry, but updated on exit to point
1080 * to the first unmatched character
1081 * @param baseValue The partial parse result prior to entering this
1082 * function
1083 * @param upperBound Only consider rules with base values lower than
1084 * this when filling in the substitution
1085 * @param lenientParse If true, try matching the text as numerals if
1086 * matching as words doesn't work
1087 * @return If the match was successful, the current partial parse
1088 * result; otherwise new Long(0). The result is either a Long or
1089 * a Double.
1090 */
1091
1092 UBool
1093 FractionalPartSubstitution::doParse(const UnicodeString& text,
1094 ParsePosition& parsePosition,
1095 double baseValue,
1096 double /*upperBound*/,
1097 UBool lenientParse,
1098 Formattable& resVal) const
1099 {
1100 // if we're not in byDigits mode, we can just use the inherited
1101 // doParse()
1102 if (!byDigits) {
1103 return NFSubstitution::doParse(text, parsePosition, baseValue, 0, lenien tParse, resVal);
1104
1105 // if we ARE in byDigits mode, parse the text one digit at a time
1106 // using this substitution's owning rule set (we do this by setting
1107 // upperBound to 10 when calling doParse() ) until we reach
1108 // nonmatching text
1109 } else {
1110 UnicodeString workText(text);
1111 ParsePosition workPos(1);
1112 double result = 0;
1113 int32_t digit;
1114 // double p10 = 0.1;
1115
1116 DigitList dl;
1117 NumberFormat* fmt = NULL;
1118 while (workText.length() > 0 && workPos.getIndex() != 0) {
1119 workPos.setIndex(0);
1120 Formattable temp;
1121 getRuleSet()->parse(workText, workPos, 10, temp);
1122 UErrorCode status = U_ZERO_ERROR;
1123 digit = temp.getLong(status);
1124 // digit = temp.getType() == Formattable::kLong ?
1125 // temp.getLong() :
1126 // (int32_t)temp.getDouble();
1127
1128 if (lenientParse && workPos.getIndex() == 0) {
1129 if (!fmt) {
1130 status = U_ZERO_ERROR;
1131 fmt = NumberFormat::createInstance(status);
1132 if (U_FAILURE(status)) {
1133 delete fmt;
1134 fmt = NULL;
1135 }
1136 }
1137 if (fmt) {
1138 fmt->parse(workText, temp, workPos);
1139 digit = temp.getLong(status);
1140 }
1141 }
1142
1143 if (workPos.getIndex() != 0) {
1144 dl.append((char)('0' + digit));
1145 // result += digit * p10;
1146 // p10 /= 10;
1147 parsePosition.setIndex(parsePosition.getIndex() + workPos.getInd ex());
1148 workText.removeBetween(0, workPos.getIndex());
1149 while (workText.length() > 0 && workText.charAt(0) == gSpace) {
1150 workText.removeBetween(0, 1);
1151 parsePosition.setIndex(parsePosition.getIndex() + 1);
1152 }
1153 }
1154 }
1155 delete fmt;
1156
1157 result = dl.getCount() == 0 ? 0 : dl.getDouble();
1158 result = composeRuleValue(result, baseValue);
1159 resVal.setDouble(result);
1160 return TRUE;
1161 }
1162 }
1163
1164 UBool
1165 FractionalPartSubstitution::operator==(const NFSubstitution& rhs) const
1166 {
1167 return NFSubstitution::operator==(rhs) &&
1168 ((const FractionalPartSubstitution*)&rhs)->byDigits == byDigits;
1169 }
1170
1171 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(FractionalPartSubstitution)
1172
1173
1174 //===================================================================
1175 // AbsoluteValueSubstitution
1176 //===================================================================
1177
1178 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(AbsoluteValueSubstitution)
1179
1180 //===================================================================
1181 // NumeratorSubstitution
1182 //===================================================================
1183
1184 void
1185 NumeratorSubstitution::doSubstitution(double number, UnicodeString& toInsertInto , int32_t apos) const {
1186 // perform a transformation on the number being formatted that
1187 // is dependent on the type of substitution this is
1188
1189 double numberToFormat = transformNumber(number);
1190 int64_t longNF = util64_fromDouble(numberToFormat);
1191
1192 const NFRuleSet* aruleSet = getRuleSet();
1193 if (withZeros && aruleSet != NULL) {
1194 // if there are leading zeros in the decimal expansion then emit them
1195 int64_t nf =longNF;
1196 int32_t len = toInsertInto.length();
1197 while ((nf *= 10) < denominator) {
1198 toInsertInto.insert(apos + getPos(), gSpace);
1199 aruleSet->format((int64_t)0, toInsertInto, apos + getPos());
1200 }
1201 apos += toInsertInto.length() - len;
1202 }
1203
1204 // if the result is an integer, from here on out we work in integer
1205 // space (saving time and memory and preserving accuracy)
1206 if (numberToFormat == longNF && aruleSet != NULL) {
1207 aruleSet->format(longNF, toInsertInto, apos + getPos());
1208
1209 // if the result isn't an integer, then call either our rule set's
1210 // format() method or our DecimalFormat's format() method to
1211 // format the result
1212 } else {
1213 if (aruleSet != NULL) {
1214 aruleSet->format(numberToFormat, toInsertInto, apos + getPos());
1215 } else {
1216 UErrorCode status = U_ZERO_ERROR;
1217 UnicodeString temp;
1218 getNumberFormat()->format(numberToFormat, temp, status);
1219 toInsertInto.insert(apos + getPos(), temp);
1220 }
1221 }
1222 }
1223
1224 UBool
1225 NumeratorSubstitution::doParse(const UnicodeString& text,
1226 ParsePosition& parsePosition,
1227 double baseValue,
1228 double upperBound,
1229 UBool /*lenientParse*/,
1230 Formattable& result) const
1231 {
1232 // we don't have to do anything special to do the parsing here,
1233 // but we have to turn lenient parsing off-- if we leave it on,
1234 // it SERIOUSLY messes up the algorithm
1235
1236 // if withZeros is true, we need to count the zeros
1237 // and use that to adjust the parse result
1238 UErrorCode status = U_ZERO_ERROR;
1239 int32_t zeroCount = 0;
1240 UnicodeString workText(text);
1241
1242 if (withZeros) {
1243 ParsePosition workPos(1);
1244 Formattable temp;
1245
1246 while (workText.length() > 0 && workPos.getIndex() != 0) {
1247 workPos.setIndex(0);
1248 getRuleSet()->parse(workText, workPos, 1, temp); // parse zero or no thing at all
1249 if (workPos.getIndex() == 0) {
1250 // we failed, either there were no more zeros, or the number was formatted with digits
1251 // either way, we're done
1252 break;
1253 }
1254
1255 ++zeroCount;
1256 parsePosition.setIndex(parsePosition.getIndex() + workPos.getIndex() );
1257 workText.remove(0, workPos.getIndex());
1258 while (workText.length() > 0 && workText.charAt(0) == gSpace) {
1259 workText.remove(0, 1);
1260 parsePosition.setIndex(parsePosition.getIndex() + 1);
1261 }
1262 }
1263
1264 workText = text;
1265 workText.remove(0, (int32_t)parsePosition.getIndex());
1266 parsePosition.setIndex(0);
1267 }
1268
1269 // we've parsed off the zeros, now let's parse the rest from our current pos ition
1270 NFSubstitution::doParse(workText, parsePosition, withZeros ? 1 : baseValue, upperBound, FALSE, result);
1271
1272 if (withZeros) {
1273 // any base value will do in this case. is there a way to
1274 // force this to not bother trying all the base values?
1275
1276 // compute the 'effective' base and prescale the value down
1277 int64_t n = result.getLong(status); // force conversion!
1278 int64_t d = 1;
1279 int32_t pow = 0;
1280 while (d <= n) {
1281 d *= 10;
1282 ++pow;
1283 }
1284 // now add the zeros
1285 while (zeroCount > 0) {
1286 d *= 10;
1287 --zeroCount;
1288 }
1289 // d is now our true denominator
1290 result.setDouble((double)n/(double)d);
1291 }
1292
1293 return TRUE;
1294 }
1295
1296 UBool
1297 NumeratorSubstitution::operator==(const NFSubstitution& rhs) const
1298 {
1299 return NFSubstitution::operator==(rhs) &&
1300 denominator == ((const NumeratorSubstitution*)&rhs)->denominator;
1301 }
1302
1303 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(NumeratorSubstitution)
1304
1305 const UChar NumeratorSubstitution::LTLT[] = { 0x003c, 0x003c };
1306
1307 //===================================================================
1308 // NullSubstitution
1309 //===================================================================
1310
1311 UOBJECT_DEFINE_RTTI_IMPLEMENTATION(NullSubstitution)
1312
1313 U_NAMESPACE_END
1314
1315 /* U_HAVE_RBNF */
1316 #endif
1317
OLDNEW
« no previous file with comments | « icu46/source/i18n/nfsubs.h ('k') | icu46/source/i18n/nortrans.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698