]> git.saurik.com Git - apple/icu.git/blame - icuSources/i18n/nfrs.cpp
ICU-551.51.4.tar.gz
[apple/icu.git] / icuSources / i18n / nfrs.cpp
CommitLineData
b75a7d8f
A
1/*
2******************************************************************************
b331163b 3* Copyright (C) 1997-2014, International Business Machines
b75a7d8f
A
4* Corporation and others. All Rights Reserved.
5******************************************************************************
6* file name: nfrs.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 "nfrs.h"
17
18#if U_HAVE_RBNF
19
20#include "unicode/uchar.h"
21#include "nfrule.h"
22#include "nfrlist.h"
4388f060 23#include "patternprops.h"
b75a7d8f
A
24
25#ifdef RBNF_DEBUG
26#include "cmemory.h"
27#endif
28
b75a7d8f
A
29U_NAMESPACE_BEGIN
30
31#if 0
32// euclid's algorithm works with doubles
33// note, doubles only get us up to one quadrillion or so, which
34// isn't as much range as we get with longs. We probably still
35// want either 64-bit math, or BigInteger.
36
37static int64_t
38util_lcm(int64_t x, int64_t y)
39{
40 x.abs();
41 y.abs();
42
43 if (x == 0 || y == 0) {
44 return 0;
45 } else {
46 do {
47 if (x < y) {
48 int64_t t = x; x = y; y = t;
49 }
50 x -= y * (x/y);
51 } while (x != 0);
52
53 return y;
54 }
55}
56
57#else
58/**
59 * Calculates the least common multiple of x and y.
60 */
61static int64_t
62util_lcm(int64_t x, int64_t y)
63{
64 // binary gcd algorithm from Knuth, "The Art of Computer Programming,"
65 // vol. 2, 1st ed., pp. 298-299
66 int64_t x1 = x;
67 int64_t y1 = y;
68
69 int p2 = 0;
70 while ((x1 & 1) == 0 && (y1 & 1) == 0) {
71 ++p2;
72 x1 >>= 1;
73 y1 >>= 1;
74 }
75
76 int64_t t;
77 if ((x1 & 1) == 1) {
78 t = -y1;
79 } else {
80 t = x1;
81 }
82
83 while (t != 0) {
84 while ((t & 1) == 0) {
85 t = t >> 1;
86 }
87 if (t > 0) {
88 x1 = t;
89 } else {
90 y1 = -t;
91 }
92 t = x1 - y1;
93 }
94
95 int64_t gcd = x1 << p2;
96
97 // x * y == gcd(x, y) * lcm(x, y)
98 return x / gcd * y;
99}
100#endif
101
102static const UChar gPercent = 0x0025;
103static const UChar gColon = 0x003a;
104static const UChar gSemicolon = 0x003b;
105static const UChar gLineFeed = 0x000a;
106
107static const UChar gFourSpaces[] =
108{
109 0x20, 0x20, 0x20, 0x20, 0
110}; /* " " */
111static const UChar gPercentPercent[] =
112{
113 0x25, 0x25, 0
114}; /* "%%" */
115
4388f060
A
116static const UChar gNoparse[] =
117{
118 0x40, 0x6E, 0x6F, 0x70, 0x61, 0x72, 0x73, 0x65, 0
119}; /* "@noparse" */
120
b75a7d8f
A
121NFRuleSet::NFRuleSet(UnicodeString* descriptions, int32_t index, UErrorCode& status)
122 : name()
123 , rules(0)
124 , negativeNumberRule(NULL)
125 , fIsFractionRuleSet(FALSE)
126 , fIsPublic(FALSE)
4388f060 127 , fIsParseable(TRUE)
374ca955 128 , fRecursionCount(0)
b75a7d8f
A
129{
130 for (int i = 0; i < 3; ++i) {
131 fractionRules[i] = NULL;
132 }
133
134 if (U_FAILURE(status)) {
135 return;
136 }
137
138 UnicodeString& description = descriptions[index]; // !!! make sure index is valid
139
374ca955
A
140 if (description.length() == 0) {
141 // throw new IllegalArgumentException("Empty rule set description");
142 status = U_PARSE_ERROR;
73c04bcf 143 return;
374ca955
A
144 }
145
b75a7d8f
A
146 // if the description begins with a rule set name (the rule set
147 // name can be omitted in formatter descriptions that consist
148 // of only one rule set), copy it out into our "name" member
149 // and delete it from the description
150 if (description.charAt(0) == gPercent) {
151 int32_t pos = description.indexOf(gColon);
152 if (pos == -1) {
153 // throw new IllegalArgumentException("Rule set name doesn't end in colon");
154 status = U_PARSE_ERROR;
155 } else {
156 name.setTo(description, 0, pos);
4388f060 157 while (pos < description.length() && PatternProps::isWhiteSpace(description.charAt(++pos))) {
b75a7d8f
A
158 }
159 description.remove(0, pos);
160 }
161 } else {
374ca955 162 name.setTo(UNICODE_STRING_SIMPLE("%default"));
b75a7d8f
A
163 }
164
165 if (description.length() == 0) {
166 // throw new IllegalArgumentException("Empty rule set description");
167 status = U_PARSE_ERROR;
168 }
169
4388f060
A
170 fIsPublic = name.indexOf(gPercentPercent, 2, 0) != 0;
171
172 if ( name.endsWith(gNoparse,8) ) {
173 fIsParseable = FALSE;
174 name.truncate(name.length()-8); // remove the @noparse from the name
175 }
b75a7d8f
A
176
177 // all of the other members of NFRuleSet are initialized
178 // by parseRules()
179}
180
181void
182NFRuleSet::parseRules(UnicodeString& description, const RuleBasedNumberFormat* owner, UErrorCode& status)
183{
184 // start by creating a Vector whose elements are Strings containing
185 // the descriptions of the rules (one rule per element). The rules
186 // are separated by semicolons (there's no escape facility: ALL
187 // semicolons are rule delimiters)
188
189 if (U_FAILURE(status)) {
190 return;
191 }
192
4388f060
A
193 // ensure we are starting with an empty rule list
194 rules.deleteAll();
195
b75a7d8f
A
196 // dlf - the original code kept a separate description array for no reason,
197 // so I got rid of it. The loop was too complex so I simplified it.
198
199 UnicodeString currentDescription;
200 int32_t oldP = 0;
201 while (oldP < description.length()) {
202 int32_t p = description.indexOf(gSemicolon, oldP);
203 if (p == -1) {
204 p = description.length();
205 }
206 currentDescription.setTo(description, oldP, p - oldP);
207 NFRule::makeRules(currentDescription, this, rules.last(), owner, rules, status);
208 oldP = p + 1;
209 }
210
211 // for rules that didn't specify a base value, their base values
212 // were initialized to 0. Make another pass through the list and
213 // set all those rules' base values. We also remove any special
214 // rules from the list and put them into their own member variables
215 int64_t defaultBaseValue = 0;
216
217 // (this isn't a for loop because we might be deleting items from
218 // the vector-- we want to make sure we only increment i when
219 // we _didn't_ delete aything from the vector)
220 uint32_t i = 0;
221 while (i < rules.size()) {
222 NFRule* rule = rules[i];
223
224 switch (rule->getType()) {
225 // if the rule's base value is 0, fill in a default
226 // base value (this will be 1 plus the preceding
227 // rule's base value for regular rule sets, and the
228 // same as the preceding rule's base value in fraction
229 // rule sets)
230 case NFRule::kNoBase:
374ca955 231 rule->setBaseValue(defaultBaseValue, status);
b75a7d8f
A
232 if (!isFractionRuleSet()) {
233 ++defaultBaseValue;
234 }
235 ++i;
236 break;
237
238 // if it's the negative-number rule, copy it into its own
239 // data member and delete it from the list
240 case NFRule::kNegativeNumberRule:
4388f060
A
241 if (negativeNumberRule) {
242 delete negativeNumberRule;
243 }
b75a7d8f
A
244 negativeNumberRule = rules.remove(i);
245 break;
246
247 // if it's the improper fraction rule, copy it into the
248 // correct element of fractionRules
249 case NFRule::kImproperFractionRule:
4388f060
A
250 if (fractionRules[0]) {
251 delete fractionRules[0];
252 }
b75a7d8f
A
253 fractionRules[0] = rules.remove(i);
254 break;
255
256 // if it's the proper fraction rule, copy it into the
257 // correct element of fractionRules
258 case NFRule::kProperFractionRule:
4388f060
A
259 if (fractionRules[1]) {
260 delete fractionRules[1];
261 }
b75a7d8f
A
262 fractionRules[1] = rules.remove(i);
263 break;
264
265 // if it's the master rule, copy it into the
266 // correct element of fractionRules
267 case NFRule::kMasterRule:
4388f060
A
268 if (fractionRules[2]) {
269 delete fractionRules[2];
270 }
b75a7d8f
A
271 fractionRules[2] = rules.remove(i);
272 break;
273
274 // if it's a regular rule that already knows its base value,
275 // check to make sure the rules are in order, and update
276 // the default base value for the next rule
277 default:
278 if (rule->getBaseValue() < defaultBaseValue) {
279 // throw new IllegalArgumentException("Rules are not in order");
280 status = U_PARSE_ERROR;
281 return;
282 }
283 defaultBaseValue = rule->getBaseValue();
284 if (!isFractionRuleSet()) {
285 ++defaultBaseValue;
286 }
287 ++i;
288 break;
289 }
290 }
291}
292
293NFRuleSet::~NFRuleSet()
294{
295 delete negativeNumberRule;
296 delete fractionRules[0];
297 delete fractionRules[1];
298 delete fractionRules[2];
299}
300
374ca955 301static UBool
b75a7d8f
A
302util_equalRules(const NFRule* rule1, const NFRule* rule2)
303{
304 if (rule1) {
305 if (rule2) {
306 return *rule1 == *rule2;
307 }
308 } else if (!rule2) {
309 return TRUE;
310 }
311 return FALSE;
312}
313
314UBool
315NFRuleSet::operator==(const NFRuleSet& rhs) const
316{
317 if (rules.size() == rhs.rules.size() &&
318 fIsFractionRuleSet == rhs.fIsFractionRuleSet &&
319 name == rhs.name &&
320 util_equalRules(negativeNumberRule, rhs.negativeNumberRule) &&
321 util_equalRules(fractionRules[0], rhs.fractionRules[0]) &&
322 util_equalRules(fractionRules[1], rhs.fractionRules[1]) &&
323 util_equalRules(fractionRules[2], rhs.fractionRules[2])) {
324
325 for (uint32_t i = 0; i < rules.size(); ++i) {
326 if (*rules[i] != *rhs.rules[i]) {
327 return FALSE;
328 }
329 }
330 return TRUE;
331 }
332 return FALSE;
333}
334
374ca955
A
335#define RECURSION_LIMIT 50
336
b75a7d8f 337void
b331163b 338NFRuleSet::format(int64_t number, UnicodeString& toAppendTo, int32_t pos, UErrorCode& status) const
b75a7d8f
A
339{
340 NFRule *rule = findNormalRule(number);
374ca955
A
341 if (rule) { // else error, but can't report it
342 NFRuleSet* ncThis = (NFRuleSet*)this;
343 if (ncThis->fRecursionCount++ >= RECURSION_LIMIT) {
344 // stop recursion
345 ncThis->fRecursionCount = 0;
346 } else {
b331163b 347 rule->doFormat(number, toAppendTo, pos, status);
374ca955
A
348 ncThis->fRecursionCount--;
349 }
350 }
b75a7d8f
A
351}
352
353void
b331163b 354NFRuleSet::format(double number, UnicodeString& toAppendTo, int32_t pos, UErrorCode& status) const
b75a7d8f
A
355{
356 NFRule *rule = findDoubleRule(number);
374ca955
A
357 if (rule) { // else error, but can't report it
358 NFRuleSet* ncThis = (NFRuleSet*)this;
359 if (ncThis->fRecursionCount++ >= RECURSION_LIMIT) {
360 // stop recursion
361 ncThis->fRecursionCount = 0;
362 } else {
b331163b 363 rule->doFormat(number, toAppendTo, pos, status);
374ca955
A
364 ncThis->fRecursionCount--;
365 }
366 }
b75a7d8f
A
367}
368
369NFRule*
370NFRuleSet::findDoubleRule(double number) const
371{
372 // if this is a fraction rule set, use findFractionRuleSetRule()
373 if (isFractionRuleSet()) {
374 return findFractionRuleSetRule(number);
375 }
376
377 // if the number is negative, return the negative number rule
378 // (if there isn't a negative-number rule, we pretend it's a
379 // positive number)
380 if (number < 0) {
381 if (negativeNumberRule) {
382 return negativeNumberRule;
383 } else {
384 number = -number;
385 }
386 }
387
388 // if the number isn't an integer, we use one of the fraction rules...
389 if (number != uprv_floor(number)) {
390 // if the number is between 0 and 1, return the proper
391 // fraction rule
392 if (number < 1 && fractionRules[1]) {
393 return fractionRules[1];
394 }
395 // otherwise, return the improper fraction rule
396 else if (fractionRules[0]) {
397 return fractionRules[0];
398 }
399 }
400
401 // if there's a master rule, use it to format the number
402 if (fractionRules[2]) {
403 return fractionRules[2];
404 }
405
729e4ab9 406 // always use the last rule for infinity. It is likely that rule
4388f060 407 // has a DecimalFormat that will do the right thing with infinity even
729e4ab9
A
408 // if the rule's base value is strange, i.e. something larger than what
409 // util64_fromDouble produces below.
410 if (uprv_isInfinite(number) && (rules.size() > 0)) {
411 return rules[rules.size() - 1];
412 }
413
b75a7d8f
A
414 // and if we haven't yet returned a rule, use findNormalRule()
415 // to find the applicable rule
416 int64_t r = util64_fromDouble(number + 0.5);
417 return findNormalRule(r);
418}
419
420NFRule *
421NFRuleSet::findNormalRule(int64_t number) const
422{
423 // if this is a fraction rule set, use findFractionRuleSetRule()
424 // to find the rule (we should only go into this clause if the
425 // value is 0)
426 if (fIsFractionRuleSet) {
427 return findFractionRuleSetRule((double)number);
428 }
429
430 // if the number is negative, return the negative-number rule
431 // (if there isn't one, pretend the number is positive)
432 if (number < 0) {
433 if (negativeNumberRule) {
434 return negativeNumberRule;
435 } else {
436 number = -number;
437 }
438 }
439
440 // we have to repeat the preceding two checks, even though we
441 // do them in findRule(), because the version of format() that
442 // takes a long bypasses findRule() and goes straight to this
443 // function. This function does skip the fraction rules since
444 // we know the value is an integer (it also skips the master
445 // rule, since it's considered a fraction rule. Skipping the
446 // master rule in this function is also how we avoid infinite
447 // recursion)
448
449 // {dlf} unfortunately this fails if there are no rules except
450 // special rules. If there are no rules, use the master rule.
451
452 // binary-search the rule list for the applicable rule
453 // (a rule is used for all values from its base value to
454 // the next rule's base value)
455 int32_t hi = rules.size();
456 if (hi > 0) {
457 int32_t lo = 0;
458
459 while (lo < hi) {
460 int32_t mid = (lo + hi) / 2;
461 if (rules[mid]->getBaseValue() == number) {
462 return rules[mid];
463 }
464 else if (rules[mid]->getBaseValue() > number) {
465 hi = mid;
466 }
467 else {
468 lo = mid + 1;
469 }
470 }
374ca955
A
471 if (hi == 0) { // bad rule set, minimum base > 0
472 return NULL; // want to throw exception here
473 }
474
b75a7d8f
A
475 NFRule *result = rules[hi - 1];
476
477 // use shouldRollBack() to see whether we need to invoke the
478 // rollback rule (see shouldRollBack()'s documentation for
479 // an explanation of the rollback rule). If we do, roll back
480 // one rule and return that one instead of the one we'd normally
481 // return
482 if (result->shouldRollBack((double)number)) {
374ca955
A
483 if (hi == 1) { // bad rule set, no prior rule to rollback to from this base
484 return NULL;
485 }
b75a7d8f
A
486 result = rules[hi - 2];
487 }
488 return result;
489 }
490 // else use the master rule
491 return fractionRules[2];
492}
493
494/**
495 * If this rule is a fraction rule set, this function is used by
496 * findRule() to select the most appropriate rule for formatting
497 * the number. Basically, the base value of each rule in the rule
498 * set is treated as the denominator of a fraction. Whichever
499 * denominator can produce the fraction closest in value to the
500 * number passed in is the result. If there's a tie, the earlier
501 * one in the list wins. (If there are two rules in a row with the
502 * same base value, the first one is used when the numerator of the
503 * fraction would be 1, and the second rule is used the rest of the
504 * time.
505 * @param number The number being formatted (which will always be
506 * a number between 0 and 1)
507 * @return The rule to use to format this number
508 */
509NFRule*
510NFRuleSet::findFractionRuleSetRule(double number) const
511{
512 // the obvious way to do this (multiply the value being formatted
513 // by each rule's base value until you get an integral result)
514 // doesn't work because of rounding error. This method is more
515 // accurate
516
517 // find the least common multiple of the rules' base values
518 // and multiply this by the number being formatted. This is
519 // all the precision we need, and we can do all of the rest
520 // of the math using integer arithmetic
521 int64_t leastCommonMultiple = rules[0]->getBaseValue();
522 int64_t numerator;
523 {
524 for (uint32_t i = 1; i < rules.size(); ++i) {
525 leastCommonMultiple = util_lcm(leastCommonMultiple, rules[i]->getBaseValue());
526 }
527 numerator = util64_fromDouble(number * (double)leastCommonMultiple + 0.5);
528 }
529 // for each rule, do the following...
530 int64_t tempDifference;
531 int64_t difference = util64_fromDouble(uprv_maxMantissa());
532 int32_t winner = 0;
533 for (uint32_t i = 0; i < rules.size(); ++i) {
534 // "numerator" is the numerator of the fraction if the
535 // denominator is the LCD. The numerator if the rule's
536 // base value is the denominator is "numerator" times the
537 // base value divided bythe LCD. Here we check to see if
538 // that's an integer, and if not, how close it is to being
539 // an integer.
540 tempDifference = numerator * rules[i]->getBaseValue() % leastCommonMultiple;
541
542
543 // normalize the result of the above calculation: we want
544 // the numerator's distance from the CLOSEST multiple
545 // of the LCD
546 if (leastCommonMultiple - tempDifference < tempDifference) {
547 tempDifference = leastCommonMultiple - tempDifference;
548 }
549
550 // if this is as close as we've come, keep track of how close
551 // that is, and the line number of the rule that did it. If
552 // we've scored a direct hit, we don't have to look at any more
553 // rules
554 if (tempDifference < difference) {
555 difference = tempDifference;
556 winner = i;
557 if (difference == 0) {
558 break;
559 }
560 }
561 }
562
563 // if we have two successive rules that both have the winning base
564 // value, then the first one (the one we found above) is used if
565 // the numerator of the fraction is 1 and the second one is used if
566 // the numerator of the fraction is anything else (this lets us
567 // do things like "one third"/"two thirds" without haveing to define
568 // a whole bunch of extra rule sets)
569 if ((unsigned)(winner + 1) < rules.size() &&
570 rules[winner + 1]->getBaseValue() == rules[winner]->getBaseValue()) {
571 double n = ((double)rules[winner]->getBaseValue()) * number;
572 if (n < 0.5 || n >= 2) {
573 ++winner;
574 }
575 }
576
577 // finally, return the winning rule
578 return rules[winner];
579}
580
581/**
582 * Parses a string. Matches the string to be parsed against each
583 * of its rules (with a base value less than upperBound) and returns
584 * the value produced by the rule that matched the most charcters
585 * in the source string.
586 * @param text The string to parse
587 * @param parsePosition The initial position is ignored and assumed
588 * to be 0. On exit, this object has been updated to point to the
589 * first character position this rule set didn't consume.
590 * @param upperBound Limits the rules that can be allowed to match.
591 * Only rules whose base values are strictly less than upperBound
592 * are considered.
593 * @return The numerical result of parsing this string. This will
594 * be the matching rule's base value, composed appropriately with
595 * the results of matching any of its substitutions. The object
596 * will be an instance of Long if it's an integral value; otherwise,
597 * it will be an instance of Double. This function always returns
598 * a valid object: If nothing matched the input string at all,
599 * this function returns new Long(0), and the parse position is
600 * left unchanged.
601 */
602#ifdef RBNF_DEBUG
603#include <stdio.h>
604
605static void dumpUS(FILE* f, const UnicodeString& us) {
606 int len = us.length();
607 char* buf = (char *)uprv_malloc((len+1)*sizeof(char)); //new char[len+1];
46f4442e
A
608 if (buf != NULL) {
609 us.extract(0, len, buf);
610 buf[len] = 0;
611 fprintf(f, "%s", buf);
612 uprv_free(buf); //delete[] buf;
613 }
b75a7d8f
A
614}
615#endif
616
617UBool
729e4ab9 618NFRuleSet::parse(const UnicodeString& text, ParsePosition& pos, double upperBound, Formattable& result, UBool lenient) const
b75a7d8f
A
619{
620 // try matching each rule in the rule set against the text being
621 // parsed. Whichever one matches the most characters is the one
622 // that determines the value we return.
623
624 result.setLong(0);
625
626 // dump out if there's no text to parse
627 if (text.length() == 0) {
628 return 0;
629 }
630
631 ParsePosition highWaterMark;
632 ParsePosition workingPos = pos;
633
634#ifdef RBNF_DEBUG
635 fprintf(stderr, "<nfrs> %x '", this);
636 dumpUS(stderr, name);
637 fprintf(stderr, "' text '");
638 dumpUS(stderr, text);
639 fprintf(stderr, "'\n");
640 fprintf(stderr, " parse negative: %d\n", this, negativeNumberRule != 0);
641#endif
642
643 // start by trying the negative number rule (if there is one)
644 if (negativeNumberRule) {
645 Formattable tempResult;
646#ifdef RBNF_DEBUG
647 fprintf(stderr, " <nfrs before negative> %x ub: %g\n", negativeNumberRule, upperBound);
648#endif
649 UBool success = negativeNumberRule->doParse(text, workingPos, 0, upperBound, tempResult);
650#ifdef RBNF_DEBUG
651 fprintf(stderr, " <nfrs after negative> success: %d wpi: %d\n", success, workingPos.getIndex());
652#endif
653 if (success && workingPos.getIndex() > highWaterMark.getIndex()) {
654 result = tempResult;
655 highWaterMark = workingPos;
656 }
657 workingPos = pos;
658 }
659#ifdef RBNF_DEBUG
660 fprintf(stderr, "<nfrs> continue fractional with text '");
661 dumpUS(stderr, text);
662 fprintf(stderr, "' hwm: %d\n", highWaterMark.getIndex());
663#endif
664 // then try each of the fraction rules
665 {
666 for (int i = 0; i < 3; i++) {
667 if (fractionRules[i]) {
668 Formattable tempResult;
729e4ab9 669 UBool success = fractionRules[i]->doParse(text, workingPos, 0, upperBound, tempResult, lenient || isDecimalFormatRuleParseable() );
b75a7d8f
A
670 if (success && (workingPos.getIndex() > highWaterMark.getIndex())) {
671 result = tempResult;
672 highWaterMark = workingPos;
673 }
674 workingPos = pos;
675 }
676 }
677 }
678#ifdef RBNF_DEBUG
679 fprintf(stderr, "<nfrs> continue other with text '");
680 dumpUS(stderr, text);
681 fprintf(stderr, "' hwm: %d\n", highWaterMark.getIndex());
682#endif
683
684 // finally, go through the regular rules one at a time. We start
685 // at the end of the list because we want to try matching the most
686 // sigificant rule first (this helps ensure that we parse
687 // "five thousand three hundred six" as
688 // "(five thousand) (three hundred) (six)" rather than
689 // "((five thousand three) hundred) (six)"). Skip rules whose
690 // base values are higher than the upper bound (again, this helps
691 // limit ambiguity by making sure the rules that match a rule's
692 // are less significant than the rule containing the substitutions)/
693 {
694 int64_t ub = util64_fromDouble(upperBound);
695#ifdef RBNF_DEBUG
696 {
697 char ubstr[64];
698 util64_toa(ub, ubstr, 64);
699 char ubstrhex[64];
700 util64_toa(ub, ubstrhex, 64, 16);
701 fprintf(stderr, "ub: %g, i64: %s (%s)\n", upperBound, ubstr, ubstrhex);
702 }
703#endif
704 for (int32_t i = rules.size(); --i >= 0 && highWaterMark.getIndex() < text.length();) {
705 if ((!fIsFractionRuleSet) && (rules[i]->getBaseValue() >= ub)) {
706 continue;
707 }
708 Formattable tempResult;
709 UBool success = rules[i]->doParse(text, workingPos, fIsFractionRuleSet, upperBound, tempResult);
710 if (success && workingPos.getIndex() > highWaterMark.getIndex()) {
711 result = tempResult;
712 highWaterMark = workingPos;
713 }
714 workingPos = pos;
715 }
716 }
717#ifdef RBNF_DEBUG
718 fprintf(stderr, "<nfrs> exit\n");
719#endif
720 // finally, update the parse postion we were passed to point to the
721 // first character we didn't use, and return the result that
722 // corresponds to that string of characters
723 pos = highWaterMark;
724
725 return 1;
726}
727
728void
729NFRuleSet::appendRules(UnicodeString& result) const
730{
731 // the rule set name goes first...
732 result.append(name);
733 result.append(gColon);
734 result.append(gLineFeed);
735
736 // followed by the regular rules...
737 for (uint32_t i = 0; i < rules.size(); i++) {
4388f060 738 result.append(gFourSpaces, 4);
73c04bcf 739 rules[i]->_appendRuleText(result);
b75a7d8f
A
740 result.append(gLineFeed);
741 }
742
743 // followed by the special rules (if they exist)
744 if (negativeNumberRule) {
4388f060 745 result.append(gFourSpaces, 4);
73c04bcf 746 negativeNumberRule->_appendRuleText(result);
b75a7d8f
A
747 result.append(gLineFeed);
748 }
749
750 {
751 for (uint32_t i = 0; i < 3; ++i) {
752 if (fractionRules[i]) {
4388f060 753 result.append(gFourSpaces, 4);
73c04bcf 754 fractionRules[i]->_appendRuleText(result);
b75a7d8f
A
755 result.append(gLineFeed);
756 }
757 }
758 }
759}
760
761// utility functions
762
763int64_t util64_fromDouble(double d) {
764 int64_t result = 0;
765 if (!uprv_isNaN(d)) {
766 double mant = uprv_maxMantissa();
767 if (d < -mant) {
768 d = -mant;
769 } else if (d > mant) {
770 d = mant;
771 }
772 UBool neg = d < 0;
773 if (neg) {
774 d = -d;
775 }
776 result = (int64_t)uprv_floor(d);
777 if (neg) {
778 result = -result;
779 }
780 }
781 return result;
782}
783
784int64_t util64_pow(int32_t r, uint32_t e) {
785 if (r == 0) {
786 return 0;
787 } else if (e == 0) {
788 return 1;
789 } else {
790 int64_t n = r;
791 while (--e > 0) {
792 n *= r;
793 }
794 return n;
795 }
796}
797
798static const uint8_t asciiDigits[] = {
799 0x30u, 0x31u, 0x32u, 0x33u, 0x34u, 0x35u, 0x36u, 0x37u,
800 0x38u, 0x39u, 0x61u, 0x62u, 0x63u, 0x64u, 0x65u, 0x66u,
801 0x67u, 0x68u, 0x69u, 0x6au, 0x6bu, 0x6cu, 0x6du, 0x6eu,
802 0x6fu, 0x70u, 0x71u, 0x72u, 0x73u, 0x74u, 0x75u, 0x76u,
803 0x77u, 0x78u, 0x79u, 0x7au,
804};
805
806static const UChar kUMinus = (UChar)0x002d;
807
73c04bcf 808#ifdef RBNF_DEBUG
b75a7d8f
A
809static const char kMinus = '-';
810
811static const uint8_t digitInfo[] = {
812 0, 0, 0, 0, 0, 0, 0, 0,
813 0, 0, 0, 0, 0, 0, 0, 0,
814 0, 0, 0, 0, 0, 0, 0, 0,
815 0, 0, 0, 0, 0, 0, 0, 0,
816 0, 0, 0, 0, 0, 0, 0, 0,
817 0, 0, 0, 0, 0, 0, 0, 0,
818 0x80u, 0x81u, 0x82u, 0x83u, 0x84u, 0x85u, 0x86u, 0x87u,
819 0x88u, 0x89u, 0, 0, 0, 0, 0, 0,
820 0, 0x8au, 0x8bu, 0x8cu, 0x8du, 0x8eu, 0x8fu, 0x90u,
821 0x91u, 0x92u, 0x93u, 0x94u, 0x95u, 0x96u, 0x97u, 0x98u,
822 0x99u, 0x9au, 0x9bu, 0x9cu, 0x9du, 0x9eu, 0x9fu, 0xa0u,
823 0xa1u, 0xa2u, 0xa3u, 0, 0, 0, 0, 0,
824 0, 0x8au, 0x8bu, 0x8cu, 0x8du, 0x8eu, 0x8fu, 0x90u,
825 0x91u, 0x92u, 0x93u, 0x94u, 0x95u, 0x96u, 0x97u, 0x98u,
826 0x99u, 0x9au, 0x9bu, 0x9cu, 0x9du, 0x9eu, 0x9fu, 0xa0u,
827 0xa1u, 0xa2u, 0xa3u, 0, 0, 0, 0, 0,
828};
829
b75a7d8f
A
830int64_t util64_atoi(const char* str, uint32_t radix)
831{
832 if (radix > 36) {
833 radix = 36;
834 } else if (radix < 2) {
835 radix = 2;
836 }
837 int64_t lradix = radix;
838
839 int neg = 0;
840 if (*str == kMinus) {
841 ++str;
842 neg = 1;
843 }
844 int64_t result = 0;
845 uint8_t b;
846 while ((b = digitInfo[*str++]) && ((b &= 0x7f) < radix)) {
847 result *= lradix;
848 result += (int32_t)b;
849 }
850 if (neg) {
851 result = -result;
852 }
853 return result;
854}
b75a7d8f
A
855
856int64_t util64_utoi(const UChar* str, uint32_t radix)
857{
858 if (radix > 36) {
859 radix = 36;
860 } else if (radix < 2) {
861 radix = 2;
862 }
863 int64_t lradix = radix;
864
865 int neg = 0;
866 if (*str == kUMinus) {
867 ++str;
868 neg = 1;
869 }
870 int64_t result = 0;
871 UChar c;
872 uint8_t b;
873 while (((c = *str++) < 0x0080) && (b = digitInfo[c]) && ((b &= 0x7f) < radix)) {
874 result *= lradix;
875 result += (int32_t)b;
876 }
877 if (neg) {
878 result = -result;
879 }
880 return result;
881}
882
b75a7d8f
A
883uint32_t util64_toa(int64_t w, char* buf, uint32_t len, uint32_t radix, UBool raw)
884{
885 if (radix > 36) {
886 radix = 36;
887 } else if (radix < 2) {
888 radix = 2;
889 }
890 int64_t base = radix;
891
892 char* p = buf;
893 if (len && (w < 0) && (radix == 10) && !raw) {
894 w = -w;
895 *p++ = kMinus;
896 --len;
897 } else if (len && (w == 0)) {
898 *p++ = (char)raw ? 0 : asciiDigits[0];
899 --len;
900 }
901
902 while (len && w != 0) {
903 int64_t n = w / base;
904 int64_t m = n * base;
905 int32_t d = (int32_t)(w-m);
906 *p++ = raw ? (char)d : asciiDigits[d];
907 w = n;
908 --len;
909 }
910 if (len) {
911 *p = 0; // null terminate if room for caller convenience
912 }
913
914 len = p - buf;
915 if (*buf == kMinus) {
916 ++buf;
917 }
918 while (--p > buf) {
919 char c = *p;
920 *p = *buf;
921 *buf = c;
922 ++buf;
923 }
924
925 return len;
926}
927#endif
928
929uint32_t util64_tou(int64_t w, UChar* buf, uint32_t len, uint32_t radix, UBool raw)
930{
931 if (radix > 36) {
932 radix = 36;
933 } else if (radix < 2) {
934 radix = 2;
935 }
936 int64_t base = radix;
937
938 UChar* p = buf;
939 if (len && (w < 0) && (radix == 10) && !raw) {
940 w = -w;
941 *p++ = kUMinus;
942 --len;
943 } else if (len && (w == 0)) {
944 *p++ = (UChar)raw ? 0 : asciiDigits[0];
945 --len;
946 }
947
948 while (len && (w != 0)) {
949 int64_t n = w / base;
950 int64_t m = n * base;
951 int32_t d = (int32_t)(w-m);
952 *p++ = (UChar)(raw ? d : asciiDigits[d]);
953 w = n;
954 --len;
955 }
956 if (len) {
957 *p = 0; // null terminate if room for caller convenience
958 }
959
960 len = (uint32_t)(p - buf);
961 if (*buf == kUMinus) {
962 ++buf;
963 }
964 while (--p > buf) {
965 UChar c = *p;
966 *p = *buf;
967 *buf = c;
968 ++buf;
969 }
970
971 return len;
972}
973
974
975U_NAMESPACE_END
976
977/* U_HAVE_RBNF */
978#endif
979