1 // © 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
4 ******************************************************************************
5 * Copyright (C) 1997-2015, International Business Machines
6 * Corporation and others. All Rights Reserved.
7 ******************************************************************************
10 * tab size: 8 (not used)
13 * Modification history
15 * 10/11/2001 Doug Ported from ICU4J
22 #include "unicode/uchar.h"
25 #include "patternprops.h"
34 NEGATIVE_RULE_INDEX
= 0,
36 IMPROPER_FRACTION_RULE_INDEX
= 1,
38 PROPER_FRACTION_RULE_INDEX
= 2,
40 MASTER_RULE_INDEX
= 3,
42 INFINITY_RULE_INDEX
= 4,
45 NON_NUMERICAL_RULE_LENGTH
= 6
51 // euclid's algorithm works with doubles
52 // note, doubles only get us up to one quadrillion or so, which
53 // isn't as much range as we get with longs. We probably still
54 // want either 64-bit math, or BigInteger.
57 util_lcm(int64_t x
, int64_t y
)
62 if (x
== 0 || y
== 0) {
67 int64_t t
= x
; x
= y
; y
= t
;
78 * Calculates the least common multiple of x and y.
81 util_lcm(int64_t x
, int64_t y
)
83 // binary gcd algorithm from Knuth, "The Art of Computer Programming,"
84 // vol. 2, 1st ed., pp. 298-299
89 while ((x1
& 1) == 0 && (y1
& 1) == 0) {
103 while ((t
& 1) == 0) {
114 int64_t gcd
= x1
<< p2
;
116 // x * y == gcd(x, y) * lcm(x, y)
121 static const UChar gPercent
= 0x0025;
122 static const UChar gColon
= 0x003a;
123 static const UChar gSemicolon
= 0x003b;
124 static const UChar gLineFeed
= 0x000a;
126 static const UChar gPercentPercent
[] =
131 static const UChar gNoparse
[] =
133 0x40, 0x6E, 0x6F, 0x70, 0x61, 0x72, 0x73, 0x65, 0
136 NFRuleSet::NFRuleSet(RuleBasedNumberFormat
*_owner
, UnicodeString
* descriptions
, int32_t index
, UErrorCode
& status
)
141 , fIsFractionRuleSet(FALSE
)
145 for (int32_t i
= 0; i
< NON_NUMERICAL_RULE_LENGTH
; ++i
) {
146 nonNumericalRules
[i
] = NULL
;
149 if (U_FAILURE(status
)) {
153 UnicodeString
& description
= descriptions
[index
]; // !!! make sure index is valid
155 if (description
.length() == 0) {
156 // throw new IllegalArgumentException("Empty rule set description");
157 status
= U_PARSE_ERROR
;
161 // if the description begins with a rule set name (the rule set
162 // name can be omitted in formatter descriptions that consist
163 // of only one rule set), copy it out into our "name" member
164 // and delete it from the description
165 if (description
.charAt(0) == gPercent
) {
166 int32_t pos
= description
.indexOf(gColon
);
168 // throw new IllegalArgumentException("Rule set name doesn't end in colon");
169 status
= U_PARSE_ERROR
;
171 name
.setTo(description
, 0, pos
);
172 while (pos
< description
.length() && PatternProps::isWhiteSpace(description
.charAt(++pos
))) {
174 description
.remove(0, pos
);
177 name
.setTo(UNICODE_STRING_SIMPLE("%default"));
180 if (description
.length() == 0) {
181 // throw new IllegalArgumentException("Empty rule set description");
182 status
= U_PARSE_ERROR
;
185 fIsPublic
= name
.indexOf(gPercentPercent
, 2, 0) != 0;
187 if ( name
.endsWith(gNoparse
,8) ) {
188 fIsParseable
= FALSE
;
189 name
.truncate(name
.length()-8); // remove the @noparse from the name
192 // all of the other members of NFRuleSet are initialized
197 NFRuleSet::parseRules(UnicodeString
& description
, UErrorCode
& status
)
199 // start by creating a Vector whose elements are Strings containing
200 // the descriptions of the rules (one rule per element). The rules
201 // are separated by semicolons (there's no escape facility: ALL
202 // semicolons are rule delimiters)
204 if (U_FAILURE(status
)) {
208 // ensure we are starting with an empty rule list
211 // dlf - the original code kept a separate description array for no reason,
212 // so I got rid of it. The loop was too complex so I simplified it.
214 UnicodeString currentDescription
;
216 while (oldP
< description
.length()) {
217 int32_t p
= description
.indexOf(gSemicolon
, oldP
);
219 p
= description
.length();
221 currentDescription
.setTo(description
, oldP
, p
- oldP
);
222 NFRule::makeRules(currentDescription
, this, rules
.last(), owner
, rules
, status
);
226 // for rules that didn't specify a base value, their base values
227 // were initialized to 0. Make another pass through the list and
228 // set all those rules' base values. We also remove any special
229 // rules from the list and put them into their own member variables
230 int64_t defaultBaseValue
= 0;
232 // (this isn't a for loop because we might be deleting items from
233 // the vector-- we want to make sure we only increment i when
234 // we _didn't_ delete aything from the vector)
235 int32_t rulesSize
= rules
.size();
236 for (int32_t i
= 0; i
< rulesSize
; i
++) {
237 NFRule
* rule
= rules
[i
];
238 int64_t baseValue
= rule
->getBaseValue();
240 if (baseValue
== 0) {
241 // if the rule's base value is 0, fill in a default
242 // base value (this will be 1 plus the preceding
243 // rule's base value for regular rule sets, and the
244 // same as the preceding rule's base value in fraction
246 rule
->setBaseValue(defaultBaseValue
, status
);
249 // if it's a regular rule that already knows its base value,
250 // check to make sure the rules are in order, and update
251 // the default base value for the next rule
252 if (baseValue
< defaultBaseValue
) {
253 // throw new IllegalArgumentException("Rules are not in order");
254 status
= U_PARSE_ERROR
;
257 defaultBaseValue
= baseValue
;
259 if (!fIsFractionRuleSet
) {
266 * Set one of the non-numerical rules.
267 * @param rule The rule to set.
269 void NFRuleSet::setNonNumericalRule(NFRule
*rule
) {
270 int64_t baseValue
= rule
->getBaseValue();
271 if (baseValue
== NFRule::kNegativeNumberRule
) {
272 delete nonNumericalRules
[NEGATIVE_RULE_INDEX
];
273 nonNumericalRules
[NEGATIVE_RULE_INDEX
] = rule
;
275 else if (baseValue
== NFRule::kImproperFractionRule
) {
276 setBestFractionRule(IMPROPER_FRACTION_RULE_INDEX
, rule
, TRUE
);
278 else if (baseValue
== NFRule::kProperFractionRule
) {
279 setBestFractionRule(PROPER_FRACTION_RULE_INDEX
, rule
, TRUE
);
281 else if (baseValue
== NFRule::kMasterRule
) {
282 setBestFractionRule(MASTER_RULE_INDEX
, rule
, TRUE
);
284 else if (baseValue
== NFRule::kInfinityRule
) {
285 delete nonNumericalRules
[INFINITY_RULE_INDEX
];
286 nonNumericalRules
[INFINITY_RULE_INDEX
] = rule
;
288 else if (baseValue
== NFRule::kNaNRule
) {
289 delete nonNumericalRules
[NAN_RULE_INDEX
];
290 nonNumericalRules
[NAN_RULE_INDEX
] = rule
;
295 * Determine the best fraction rule to use. Rules matching the decimal point from
296 * DecimalFormatSymbols become the main set of rules to use.
297 * @param originalIndex The index into nonNumericalRules
298 * @param newRule The new rule to consider
299 * @param rememberRule Should the new rule be added to fractionRules.
301 void NFRuleSet::setBestFractionRule(int32_t originalIndex
, NFRule
*newRule
, UBool rememberRule
) {
303 fractionRules
.add(newRule
);
305 NFRule
*bestResult
= nonNumericalRules
[originalIndex
];
306 if (bestResult
== NULL
) {
307 nonNumericalRules
[originalIndex
] = newRule
;
310 // We have more than one. Which one is better?
311 const DecimalFormatSymbols
*decimalFormatSymbols
= owner
->getDecimalFormatSymbols();
312 if (decimalFormatSymbols
->getSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol
).charAt(0)
313 == newRule
->getDecimalPoint())
315 nonNumericalRules
[originalIndex
] = newRule
;
317 // else leave it alone
321 NFRuleSet::~NFRuleSet()
323 for (int i
= 0; i
< NON_NUMERICAL_RULE_LENGTH
; i
++) {
324 if (i
!= IMPROPER_FRACTION_RULE_INDEX
325 && i
!= PROPER_FRACTION_RULE_INDEX
326 && i
!= MASTER_RULE_INDEX
)
328 delete nonNumericalRules
[i
];
330 // else it will be deleted via NFRuleList fractionRules
335 util_equalRules(const NFRule
* rule1
, const NFRule
* rule2
)
339 return *rule1
== *rule2
;
348 NFRuleSet::operator==(const NFRuleSet
& rhs
) const
350 if (rules
.size() == rhs
.rules
.size() &&
351 fIsFractionRuleSet
== rhs
.fIsFractionRuleSet
&&
354 // ...then compare the non-numerical rule lists...
355 for (int i
= 0; i
< NON_NUMERICAL_RULE_LENGTH
; i
++) {
356 if (!util_equalRules(nonNumericalRules
[i
], rhs
.nonNumericalRules
[i
])) {
361 // ...then compare the rule lists...
362 for (uint32_t i
= 0; i
< rules
.size(); ++i
) {
363 if (*rules
[i
] != *rhs
.rules
[i
]) {
373 NFRuleSet::setDecimalFormatSymbols(const DecimalFormatSymbols
&newSymbols
, UErrorCode
& status
) {
374 for (uint32_t i
= 0; i
< rules
.size(); ++i
) {
375 rules
[i
]->setDecimalFormatSymbols(newSymbols
, status
);
377 // Switch the fraction rules to mirror the DecimalFormatSymbols.
378 for (int32_t nonNumericalIdx
= IMPROPER_FRACTION_RULE_INDEX
; nonNumericalIdx
<= MASTER_RULE_INDEX
; nonNumericalIdx
++) {
379 if (nonNumericalRules
[nonNumericalIdx
]) {
380 for (uint32_t fIdx
= 0; fIdx
< fractionRules
.size(); fIdx
++) {
381 NFRule
*fractionRule
= fractionRules
[fIdx
];
382 if (nonNumericalRules
[nonNumericalIdx
]->getBaseValue() == fractionRule
->getBaseValue()) {
383 setBestFractionRule(nonNumericalIdx
, fractionRule
, FALSE
);
389 for (uint32_t nnrIdx
= 0; nnrIdx
< NON_NUMERICAL_RULE_LENGTH
; nnrIdx
++) {
390 NFRule
*rule
= nonNumericalRules
[nnrIdx
];
392 rule
->setDecimalFormatSymbols(newSymbols
, status
);
397 #define RECURSION_LIMIT 64
400 NFRuleSet::format(int64_t number
, UnicodeString
& toAppendTo
, int32_t pos
, int32_t recursionCount
, UErrorCode
& status
) const
402 if (recursionCount
>= RECURSION_LIMIT
) {
404 status
= U_INVALID_STATE_ERROR
;
407 const NFRule
*rule
= findNormalRule(number
);
408 if (rule
) { // else error, but can't report it
409 rule
->doFormat(number
, toAppendTo
, pos
, ++recursionCount
, status
);
414 NFRuleSet::format(double number
, UnicodeString
& toAppendTo
, int32_t pos
, int32_t recursionCount
, UErrorCode
& status
) const
416 if (recursionCount
>= RECURSION_LIMIT
) {
418 status
= U_INVALID_STATE_ERROR
;
421 const NFRule
*rule
= findDoubleRule(number
);
422 if (rule
) { // else error, but can't report it
423 rule
->doFormat(number
, toAppendTo
, pos
, ++recursionCount
, status
);
428 NFRuleSet::findDoubleRule(double number
) const
430 // if this is a fraction rule set, use findFractionRuleSetRule()
431 if (isFractionRuleSet()) {
432 return findFractionRuleSetRule(number
);
435 if (uprv_isNaN(number
)) {
436 const NFRule
*rule
= nonNumericalRules
[NAN_RULE_INDEX
];
438 rule
= owner
->getDefaultNaNRule();
443 // if the number is negative, return the negative number rule
444 // (if there isn't a negative-number rule, we pretend it's a
447 if (nonNumericalRules
[NEGATIVE_RULE_INDEX
]) {
448 return nonNumericalRules
[NEGATIVE_RULE_INDEX
];
454 if (uprv_isInfinite(number
)) {
455 const NFRule
*rule
= nonNumericalRules
[INFINITY_RULE_INDEX
];
457 rule
= owner
->getDefaultInfinityRule();
462 // if the number isn't an integer, we use one of the fraction rules...
463 if (number
!= uprv_floor(number
)) {
464 // if the number is between 0 and 1, return the proper
466 if (number
< 1 && nonNumericalRules
[PROPER_FRACTION_RULE_INDEX
]) {
467 return nonNumericalRules
[PROPER_FRACTION_RULE_INDEX
];
469 // otherwise, return the improper fraction rule
470 else if (nonNumericalRules
[IMPROPER_FRACTION_RULE_INDEX
]) {
471 return nonNumericalRules
[IMPROPER_FRACTION_RULE_INDEX
];
475 // if there's a master rule, use it to format the number
476 if (nonNumericalRules
[MASTER_RULE_INDEX
]) {
477 return nonNumericalRules
[MASTER_RULE_INDEX
];
480 // and if we haven't yet returned a rule, use findNormalRule()
481 // to find the applicable rule
482 int64_t r
= util64_fromDouble(number
+ 0.5);
483 return findNormalRule(r
);
487 NFRuleSet::findNormalRule(int64_t number
) const
489 // if this is a fraction rule set, use findFractionRuleSetRule()
490 // to find the rule (we should only go into this clause if the
492 if (fIsFractionRuleSet
) {
493 return findFractionRuleSetRule((double)number
);
496 // if the number is negative, return the negative-number rule
497 // (if there isn't one, pretend the number is positive)
499 if (nonNumericalRules
[NEGATIVE_RULE_INDEX
]) {
500 return nonNumericalRules
[NEGATIVE_RULE_INDEX
];
506 // we have to repeat the preceding two checks, even though we
507 // do them in findRule(), because the version of format() that
508 // takes a long bypasses findRule() and goes straight to this
509 // function. This function does skip the fraction rules since
510 // we know the value is an integer (it also skips the master
511 // rule, since it's considered a fraction rule. Skipping the
512 // master rule in this function is also how we avoid infinite
515 // {dlf} unfortunately this fails if there are no rules except
516 // special rules. If there are no rules, use the master rule.
518 // binary-search the rule list for the applicable rule
519 // (a rule is used for all values from its base value to
520 // the next rule's base value)
521 int32_t hi
= rules
.size();
526 int32_t mid
= (lo
+ hi
) / 2;
527 if (rules
[mid
]->getBaseValue() == number
) {
530 else if (rules
[mid
]->getBaseValue() > number
) {
537 if (hi
== 0) { // bad rule set, minimum base > 0
538 return NULL
; // want to throw exception here
541 NFRule
*result
= rules
[hi
- 1];
543 // use shouldRollBack() to see whether we need to invoke the
544 // rollback rule (see shouldRollBack()'s documentation for
545 // an explanation of the rollback rule). If we do, roll back
546 // one rule and return that one instead of the one we'd normally
548 if (result
->shouldRollBack(number
)) {
549 if (hi
== 1) { // bad rule set, no prior rule to rollback to from this base
552 result
= rules
[hi
- 2];
556 // else use the master rule
557 return nonNumericalRules
[MASTER_RULE_INDEX
];
561 * If this rule is a fraction rule set, this function is used by
562 * findRule() to select the most appropriate rule for formatting
563 * the number. Basically, the base value of each rule in the rule
564 * set is treated as the denominator of a fraction. Whichever
565 * denominator can produce the fraction closest in value to the
566 * number passed in is the result. If there's a tie, the earlier
567 * one in the list wins. (If there are two rules in a row with the
568 * same base value, the first one is used when the numerator of the
569 * fraction would be 1, and the second rule is used the rest of the
571 * @param number The number being formatted (which will always be
572 * a number between 0 and 1)
573 * @return The rule to use to format this number
576 NFRuleSet::findFractionRuleSetRule(double number
) const
578 // the obvious way to do this (multiply the value being formatted
579 // by each rule's base value until you get an integral result)
580 // doesn't work because of rounding error. This method is more
583 // find the least common multiple of the rules' base values
584 // and multiply this by the number being formatted. This is
585 // all the precision we need, and we can do all of the rest
586 // of the math using integer arithmetic
587 int64_t leastCommonMultiple
= rules
[0]->getBaseValue();
590 for (uint32_t i
= 1; i
< rules
.size(); ++i
) {
591 leastCommonMultiple
= util_lcm(leastCommonMultiple
, rules
[i
]->getBaseValue());
593 numerator
= util64_fromDouble(number
* (double)leastCommonMultiple
+ 0.5);
595 // for each rule, do the following...
596 int64_t tempDifference
;
597 int64_t difference
= util64_fromDouble(uprv_maxMantissa());
599 for (uint32_t i
= 0; i
< rules
.size(); ++i
) {
600 // "numerator" is the numerator of the fraction if the
601 // denominator is the LCD. The numerator if the rule's
602 // base value is the denominator is "numerator" times the
603 // base value divided bythe LCD. Here we check to see if
604 // that's an integer, and if not, how close it is to being
606 tempDifference
= numerator
* rules
[i
]->getBaseValue() % leastCommonMultiple
;
609 // normalize the result of the above calculation: we want
610 // the numerator's distance from the CLOSEST multiple
612 if (leastCommonMultiple
- tempDifference
< tempDifference
) {
613 tempDifference
= leastCommonMultiple
- tempDifference
;
616 // if this is as close as we've come, keep track of how close
617 // that is, and the line number of the rule that did it. If
618 // we've scored a direct hit, we don't have to look at any more
620 if (tempDifference
< difference
) {
621 difference
= tempDifference
;
623 if (difference
== 0) {
629 // if we have two successive rules that both have the winning base
630 // value, then the first one (the one we found above) is used if
631 // the numerator of the fraction is 1 and the second one is used if
632 // the numerator of the fraction is anything else (this lets us
633 // do things like "one third"/"two thirds" without haveing to define
634 // a whole bunch of extra rule sets)
635 if ((unsigned)(winner
+ 1) < rules
.size() &&
636 rules
[winner
+ 1]->getBaseValue() == rules
[winner
]->getBaseValue()) {
637 double n
= ((double)rules
[winner
]->getBaseValue()) * number
;
638 if (n
< 0.5 || n
>= 2) {
643 // finally, return the winning rule
644 return rules
[winner
];
648 * Parses a string. Matches the string to be parsed against each
649 * of its rules (with a base value less than upperBound) and returns
650 * the value produced by the rule that matched the most charcters
651 * in the source string.
652 * @param text The string to parse
653 * @param parsePosition The initial position is ignored and assumed
654 * to be 0. On exit, this object has been updated to point to the
655 * first character position this rule set didn't consume.
656 * @param upperBound Limits the rules that can be allowed to match.
657 * Only rules whose base values are strictly less than upperBound
659 * @return The numerical result of parsing this string. This will
660 * be the matching rule's base value, composed appropriately with
661 * the results of matching any of its substitutions. The object
662 * will be an instance of Long if it's an integral value; otherwise,
663 * it will be an instance of Double. This function always returns
664 * a valid object: If nothing matched the input string at all,
665 * this function returns new Long(0), and the parse position is
671 static void dumpUS(FILE* f
, const UnicodeString
& us
) {
672 int len
= us
.length();
673 char* buf
= (char *)uprv_malloc((len
+1)*sizeof(char)); //new char[len+1];
675 us
.extract(0, len
, buf
);
677 fprintf(f
, "%s", buf
);
678 uprv_free(buf
); //delete[] buf;
684 NFRuleSet::parse(const UnicodeString
& text
, ParsePosition
& pos
, double upperBound
, Formattable
& result
, UBool lenient
) const
686 // try matching each rule in the rule set against the text being
687 // parsed. Whichever one matches the most characters is the one
688 // that determines the value we return.
692 // dump out if there's no text to parse
693 if (text
.length() == 0) {
697 ParsePosition highWaterMark
;
698 ParsePosition workingPos
= pos
;
701 fprintf(stderr
, "<nfrs> %x '", this);
702 dumpUS(stderr
, name
);
703 fprintf(stderr
, "' text '");
704 dumpUS(stderr
, text
);
705 fprintf(stderr
, "'\n");
706 fprintf(stderr
, " parse negative: %d\n", this, negativeNumberRule
!= 0);
708 // Try each of the negative rules, fraction rules, infinity rules and NaN rules
709 for (int i
= 0; i
< NON_NUMERICAL_RULE_LENGTH
; i
++) {
710 if (nonNumericalRules
[i
]) {
711 Formattable tempResult
;
712 UBool success
= nonNumericalRules
[i
]->doParse(text
, workingPos
, 0, upperBound
, tempResult
, lenient
|| isDecimalFormatRuleParseable() );
713 if (success
&& (workingPos
.getIndex() > highWaterMark
.getIndex())) {
715 highWaterMark
= workingPos
;
721 fprintf(stderr
, "<nfrs> continue other with text '");
722 dumpUS(stderr
, text
);
723 fprintf(stderr
, "' hwm: %d\n", highWaterMark
.getIndex());
726 // finally, go through the regular rules one at a time. We start
727 // at the end of the list because we want to try matching the most
728 // sigificant rule first (this helps ensure that we parse
729 // "five thousand three hundred six" as
730 // "(five thousand) (three hundred) (six)" rather than
731 // "((five thousand three) hundred) (six)"). Skip rules whose
732 // base values are higher than the upper bound (again, this helps
733 // limit ambiguity by making sure the rules that match a rule's
734 // are less significant than the rule containing the substitutions)/
736 int64_t ub
= util64_fromDouble(upperBound
);
740 util64_toa(ub
, ubstr
, 64);
742 util64_toa(ub
, ubstrhex
, 64, 16);
743 fprintf(stderr
, "ub: %g, i64: %s (%s)\n", upperBound
, ubstr
, ubstrhex
);
746 for (int32_t i
= rules
.size(); --i
>= 0 && highWaterMark
.getIndex() < text
.length();) {
747 if ((!fIsFractionRuleSet
) && (rules
[i
]->getBaseValue() >= ub
)) {
750 Formattable tempResult
;
751 UBool success
= rules
[i
]->doParse(text
, workingPos
, fIsFractionRuleSet
, upperBound
, tempResult
);
752 if (success
&& workingPos
.getIndex() > highWaterMark
.getIndex()) {
754 highWaterMark
= workingPos
;
760 fprintf(stderr
, "<nfrs> exit\n");
762 // finally, update the parse postion we were passed to point to the
763 // first character we didn't use, and return the result that
764 // corresponds to that string of characters
771 NFRuleSet::appendRules(UnicodeString
& result
) const
775 // the rule set name goes first...
777 result
.append(gColon
);
778 result
.append(gLineFeed
);
780 // followed by the regular rules...
781 for (i
= 0; i
< rules
.size(); i
++) {
782 rules
[i
]->_appendRuleText(result
);
783 result
.append(gLineFeed
);
786 // followed by the special rules (if they exist)
787 for (i
= 0; i
< NON_NUMERICAL_RULE_LENGTH
; ++i
) {
788 NFRule
*rule
= nonNumericalRules
[i
];
789 if (nonNumericalRules
[i
]) {
790 if (rule
->getBaseValue() == NFRule::kImproperFractionRule
791 || rule
->getBaseValue() == NFRule::kProperFractionRule
792 || rule
->getBaseValue() == NFRule::kMasterRule
)
794 for (uint32_t fIdx
= 0; fIdx
< fractionRules
.size(); fIdx
++) {
795 NFRule
*fractionRule
= fractionRules
[fIdx
];
796 if (fractionRule
->getBaseValue() == rule
->getBaseValue()) {
797 fractionRule
->_appendRuleText(result
);
798 result
.append(gLineFeed
);
803 rule
->_appendRuleText(result
);
804 result
.append(gLineFeed
);
812 int64_t util64_fromDouble(double d
) {
814 if (!uprv_isNaN(d
)) {
815 double mant
= uprv_maxMantissa();
818 } else if (d
> mant
) {
825 result
= (int64_t)uprv_floor(d
);
833 int64_t util64_pow(int32_t base
, uint16_t exponent
) {
839 while (exponent
> 0) {
840 if ((exponent
& 1) == 1) {
849 static const uint8_t asciiDigits
[] = {
850 0x30u
, 0x31u
, 0x32u
, 0x33u
, 0x34u
, 0x35u
, 0x36u
, 0x37u
,
851 0x38u
, 0x39u
, 0x61u
, 0x62u
, 0x63u
, 0x64u
, 0x65u
, 0x66u
,
852 0x67u
, 0x68u
, 0x69u
, 0x6au
, 0x6bu
, 0x6cu
, 0x6du
, 0x6eu
,
853 0x6fu
, 0x70u
, 0x71u
, 0x72u
, 0x73u
, 0x74u
, 0x75u
, 0x76u
,
854 0x77u
, 0x78u
, 0x79u
, 0x7au
,
857 static const UChar kUMinus
= (UChar
)0x002d;
860 static const char kMinus
= '-';
862 static const uint8_t digitInfo
[] = {
863 0, 0, 0, 0, 0, 0, 0, 0,
864 0, 0, 0, 0, 0, 0, 0, 0,
865 0, 0, 0, 0, 0, 0, 0, 0,
866 0, 0, 0, 0, 0, 0, 0, 0,
867 0, 0, 0, 0, 0, 0, 0, 0,
868 0, 0, 0, 0, 0, 0, 0, 0,
869 0x80u
, 0x81u
, 0x82u
, 0x83u
, 0x84u
, 0x85u
, 0x86u
, 0x87u
,
870 0x88u
, 0x89u
, 0, 0, 0, 0, 0, 0,
871 0, 0x8au
, 0x8bu
, 0x8cu
, 0x8du
, 0x8eu
, 0x8fu
, 0x90u
,
872 0x91u
, 0x92u
, 0x93u
, 0x94u
, 0x95u
, 0x96u
, 0x97u
, 0x98u
,
873 0x99u
, 0x9au
, 0x9bu
, 0x9cu
, 0x9du
, 0x9eu
, 0x9fu
, 0xa0u
,
874 0xa1u
, 0xa2u
, 0xa3u
, 0, 0, 0, 0, 0,
875 0, 0x8au
, 0x8bu
, 0x8cu
, 0x8du
, 0x8eu
, 0x8fu
, 0x90u
,
876 0x91u
, 0x92u
, 0x93u
, 0x94u
, 0x95u
, 0x96u
, 0x97u
, 0x98u
,
877 0x99u
, 0x9au
, 0x9bu
, 0x9cu
, 0x9du
, 0x9eu
, 0x9fu
, 0xa0u
,
878 0xa1u
, 0xa2u
, 0xa3u
, 0, 0, 0, 0, 0,
881 int64_t util64_atoi(const char* str
, uint32_t radix
)
885 } else if (radix
< 2) {
888 int64_t lradix
= radix
;
891 if (*str
== kMinus
) {
897 while ((b
= digitInfo
[*str
++]) && ((b
&= 0x7f) < radix
)) {
899 result
+= (int32_t)b
;
907 int64_t util64_utoi(const UChar
* str
, uint32_t radix
)
911 } else if (radix
< 2) {
914 int64_t lradix
= radix
;
917 if (*str
== kUMinus
) {
924 while (((c
= *str
++) < 0x0080) && (b
= digitInfo
[c
]) && ((b
&= 0x7f) < radix
)) {
926 result
+= (int32_t)b
;
934 uint32_t util64_toa(int64_t w
, char* buf
, uint32_t len
, uint32_t radix
, UBool raw
)
938 } else if (radix
< 2) {
941 int64_t base
= radix
;
944 if (len
&& (w
< 0) && (radix
== 10) && !raw
) {
948 } else if (len
&& (w
== 0)) {
949 *p
++ = (char)raw
? 0 : asciiDigits
[0];
953 while (len
&& w
!= 0) {
954 int64_t n
= w
/ base
;
955 int64_t m
= n
* base
;
956 int32_t d
= (int32_t)(w
-m
);
957 *p
++ = raw
? (char)d
: asciiDigits
[d
];
962 *p
= 0; // null terminate if room for caller convenience
966 if (*buf
== kMinus
) {
980 uint32_t util64_tou(int64_t w
, UChar
* buf
, uint32_t len
, uint32_t radix
, UBool raw
)
984 } else if (radix
< 2) {
987 int64_t base
= radix
;
990 if (len
&& (w
< 0) && (radix
== 10) && !raw
) {
994 } else if (len
&& (w
== 0)) {
995 *p
++ = (UChar
)raw
? 0 : asciiDigits
[0];
999 while (len
&& (w
!= 0)) {
1000 int64_t n
= w
/ base
;
1001 int64_t m
= n
* base
;
1002 int32_t d
= (int32_t)(w
-m
);
1003 *p
++ = (UChar
)(raw
? d
: asciiDigits
[d
]);
1008 *p
= 0; // null terminate if room for caller convenience
1011 len
= (uint32_t)(p
- buf
);
1012 if (*buf
== kUMinus
) {