11cb0ef41Sopenharmony_ci// © 2016 and later: Unicode, Inc. and others. 21cb0ef41Sopenharmony_ci// License & terms of use: http://www.unicode.org/copyright.html 31cb0ef41Sopenharmony_ci/* 41cb0ef41Sopenharmony_ci****************************************************************************** 51cb0ef41Sopenharmony_ci* Copyright (C) 1997-2015, International Business Machines 61cb0ef41Sopenharmony_ci* Corporation and others. All Rights Reserved. 71cb0ef41Sopenharmony_ci****************************************************************************** 81cb0ef41Sopenharmony_ci* file name: nfrs.cpp 91cb0ef41Sopenharmony_ci* encoding: UTF-8 101cb0ef41Sopenharmony_ci* tab size: 8 (not used) 111cb0ef41Sopenharmony_ci* indentation:4 121cb0ef41Sopenharmony_ci* 131cb0ef41Sopenharmony_ci* Modification history 141cb0ef41Sopenharmony_ci* Date Name Comments 151cb0ef41Sopenharmony_ci* 10/11/2001 Doug Ported from ICU4J 161cb0ef41Sopenharmony_ci*/ 171cb0ef41Sopenharmony_ci 181cb0ef41Sopenharmony_ci#include "nfrs.h" 191cb0ef41Sopenharmony_ci 201cb0ef41Sopenharmony_ci#if U_HAVE_RBNF 211cb0ef41Sopenharmony_ci 221cb0ef41Sopenharmony_ci#include "unicode/uchar.h" 231cb0ef41Sopenharmony_ci#include "nfrule.h" 241cb0ef41Sopenharmony_ci#include "nfrlist.h" 251cb0ef41Sopenharmony_ci#include "patternprops.h" 261cb0ef41Sopenharmony_ci#include "putilimp.h" 271cb0ef41Sopenharmony_ci 281cb0ef41Sopenharmony_ci#ifdef RBNF_DEBUG 291cb0ef41Sopenharmony_ci#include "cmemory.h" 301cb0ef41Sopenharmony_ci#endif 311cb0ef41Sopenharmony_ci 321cb0ef41Sopenharmony_cienum { 331cb0ef41Sopenharmony_ci /** -x */ 341cb0ef41Sopenharmony_ci NEGATIVE_RULE_INDEX = 0, 351cb0ef41Sopenharmony_ci /** x.x */ 361cb0ef41Sopenharmony_ci IMPROPER_FRACTION_RULE_INDEX = 1, 371cb0ef41Sopenharmony_ci /** 0.x */ 381cb0ef41Sopenharmony_ci PROPER_FRACTION_RULE_INDEX = 2, 391cb0ef41Sopenharmony_ci /** x.0 */ 401cb0ef41Sopenharmony_ci DEFAULT_RULE_INDEX = 3, 411cb0ef41Sopenharmony_ci /** Inf */ 421cb0ef41Sopenharmony_ci INFINITY_RULE_INDEX = 4, 431cb0ef41Sopenharmony_ci /** NaN */ 441cb0ef41Sopenharmony_ci NAN_RULE_INDEX = 5, 451cb0ef41Sopenharmony_ci NON_NUMERICAL_RULE_LENGTH = 6 461cb0ef41Sopenharmony_ci}; 471cb0ef41Sopenharmony_ci 481cb0ef41Sopenharmony_ciU_NAMESPACE_BEGIN 491cb0ef41Sopenharmony_ci 501cb0ef41Sopenharmony_ci#if 0 511cb0ef41Sopenharmony_ci// euclid's algorithm works with doubles 521cb0ef41Sopenharmony_ci// note, doubles only get us up to one quadrillion or so, which 531cb0ef41Sopenharmony_ci// isn't as much range as we get with longs. We probably still 541cb0ef41Sopenharmony_ci// want either 64-bit math, or BigInteger. 551cb0ef41Sopenharmony_ci 561cb0ef41Sopenharmony_cistatic int64_t 571cb0ef41Sopenharmony_ciutil_lcm(int64_t x, int64_t y) 581cb0ef41Sopenharmony_ci{ 591cb0ef41Sopenharmony_ci x.abs(); 601cb0ef41Sopenharmony_ci y.abs(); 611cb0ef41Sopenharmony_ci 621cb0ef41Sopenharmony_ci if (x == 0 || y == 0) { 631cb0ef41Sopenharmony_ci return 0; 641cb0ef41Sopenharmony_ci } else { 651cb0ef41Sopenharmony_ci do { 661cb0ef41Sopenharmony_ci if (x < y) { 671cb0ef41Sopenharmony_ci int64_t t = x; x = y; y = t; 681cb0ef41Sopenharmony_ci } 691cb0ef41Sopenharmony_ci x -= y * (x/y); 701cb0ef41Sopenharmony_ci } while (x != 0); 711cb0ef41Sopenharmony_ci 721cb0ef41Sopenharmony_ci return y; 731cb0ef41Sopenharmony_ci } 741cb0ef41Sopenharmony_ci} 751cb0ef41Sopenharmony_ci 761cb0ef41Sopenharmony_ci#else 771cb0ef41Sopenharmony_ci/** 781cb0ef41Sopenharmony_ci * Calculates the least common multiple of x and y. 791cb0ef41Sopenharmony_ci */ 801cb0ef41Sopenharmony_cistatic int64_t 811cb0ef41Sopenharmony_ciutil_lcm(int64_t x, int64_t y) 821cb0ef41Sopenharmony_ci{ 831cb0ef41Sopenharmony_ci // binary gcd algorithm from Knuth, "The Art of Computer Programming," 841cb0ef41Sopenharmony_ci // vol. 2, 1st ed., pp. 298-299 851cb0ef41Sopenharmony_ci int64_t x1 = x; 861cb0ef41Sopenharmony_ci int64_t y1 = y; 871cb0ef41Sopenharmony_ci 881cb0ef41Sopenharmony_ci int p2 = 0; 891cb0ef41Sopenharmony_ci while ((x1 & 1) == 0 && (y1 & 1) == 0) { 901cb0ef41Sopenharmony_ci ++p2; 911cb0ef41Sopenharmony_ci x1 >>= 1; 921cb0ef41Sopenharmony_ci y1 >>= 1; 931cb0ef41Sopenharmony_ci } 941cb0ef41Sopenharmony_ci 951cb0ef41Sopenharmony_ci int64_t t; 961cb0ef41Sopenharmony_ci if ((x1 & 1) == 1) { 971cb0ef41Sopenharmony_ci t = -y1; 981cb0ef41Sopenharmony_ci } else { 991cb0ef41Sopenharmony_ci t = x1; 1001cb0ef41Sopenharmony_ci } 1011cb0ef41Sopenharmony_ci 1021cb0ef41Sopenharmony_ci while (t != 0) { 1031cb0ef41Sopenharmony_ci while ((t & 1) == 0) { 1041cb0ef41Sopenharmony_ci t = t >> 1; 1051cb0ef41Sopenharmony_ci } 1061cb0ef41Sopenharmony_ci if (t > 0) { 1071cb0ef41Sopenharmony_ci x1 = t; 1081cb0ef41Sopenharmony_ci } else { 1091cb0ef41Sopenharmony_ci y1 = -t; 1101cb0ef41Sopenharmony_ci } 1111cb0ef41Sopenharmony_ci t = x1 - y1; 1121cb0ef41Sopenharmony_ci } 1131cb0ef41Sopenharmony_ci 1141cb0ef41Sopenharmony_ci int64_t gcd = x1 << p2; 1151cb0ef41Sopenharmony_ci 1161cb0ef41Sopenharmony_ci // x * y == gcd(x, y) * lcm(x, y) 1171cb0ef41Sopenharmony_ci return x / gcd * y; 1181cb0ef41Sopenharmony_ci} 1191cb0ef41Sopenharmony_ci#endif 1201cb0ef41Sopenharmony_ci 1211cb0ef41Sopenharmony_cistatic const char16_t gPercent = 0x0025; 1221cb0ef41Sopenharmony_cistatic const char16_t gColon = 0x003a; 1231cb0ef41Sopenharmony_cistatic const char16_t gSemicolon = 0x003b; 1241cb0ef41Sopenharmony_cistatic const char16_t gLineFeed = 0x000a; 1251cb0ef41Sopenharmony_ci 1261cb0ef41Sopenharmony_cistatic const char16_t gPercentPercent[] = 1271cb0ef41Sopenharmony_ci{ 1281cb0ef41Sopenharmony_ci 0x25, 0x25, 0 1291cb0ef41Sopenharmony_ci}; /* "%%" */ 1301cb0ef41Sopenharmony_ci 1311cb0ef41Sopenharmony_cistatic const char16_t gNoparse[] = 1321cb0ef41Sopenharmony_ci{ 1331cb0ef41Sopenharmony_ci 0x40, 0x6E, 0x6F, 0x70, 0x61, 0x72, 0x73, 0x65, 0 1341cb0ef41Sopenharmony_ci}; /* "@noparse" */ 1351cb0ef41Sopenharmony_ci 1361cb0ef41Sopenharmony_ciNFRuleSet::NFRuleSet(RuleBasedNumberFormat *_owner, UnicodeString* descriptions, int32_t index, UErrorCode& status) 1371cb0ef41Sopenharmony_ci : name() 1381cb0ef41Sopenharmony_ci , rules(0) 1391cb0ef41Sopenharmony_ci , owner(_owner) 1401cb0ef41Sopenharmony_ci , fractionRules() 1411cb0ef41Sopenharmony_ci , fIsFractionRuleSet(false) 1421cb0ef41Sopenharmony_ci , fIsPublic(false) 1431cb0ef41Sopenharmony_ci , fIsParseable(true) 1441cb0ef41Sopenharmony_ci{ 1451cb0ef41Sopenharmony_ci for (int32_t i = 0; i < NON_NUMERICAL_RULE_LENGTH; ++i) { 1461cb0ef41Sopenharmony_ci nonNumericalRules[i] = nullptr; 1471cb0ef41Sopenharmony_ci } 1481cb0ef41Sopenharmony_ci 1491cb0ef41Sopenharmony_ci if (U_FAILURE(status)) { 1501cb0ef41Sopenharmony_ci return; 1511cb0ef41Sopenharmony_ci } 1521cb0ef41Sopenharmony_ci 1531cb0ef41Sopenharmony_ci UnicodeString& description = descriptions[index]; // !!! make sure index is valid 1541cb0ef41Sopenharmony_ci 1551cb0ef41Sopenharmony_ci if (description.length() == 0) { 1561cb0ef41Sopenharmony_ci // throw new IllegalArgumentException("Empty rule set description"); 1571cb0ef41Sopenharmony_ci status = U_PARSE_ERROR; 1581cb0ef41Sopenharmony_ci return; 1591cb0ef41Sopenharmony_ci } 1601cb0ef41Sopenharmony_ci 1611cb0ef41Sopenharmony_ci // if the description begins with a rule set name (the rule set 1621cb0ef41Sopenharmony_ci // name can be omitted in formatter descriptions that consist 1631cb0ef41Sopenharmony_ci // of only one rule set), copy it out into our "name" member 1641cb0ef41Sopenharmony_ci // and delete it from the description 1651cb0ef41Sopenharmony_ci if (description.charAt(0) == gPercent) { 1661cb0ef41Sopenharmony_ci int32_t pos = description.indexOf(gColon); 1671cb0ef41Sopenharmony_ci if (pos == -1) { 1681cb0ef41Sopenharmony_ci // throw new IllegalArgumentException("Rule set name doesn't end in colon"); 1691cb0ef41Sopenharmony_ci status = U_PARSE_ERROR; 1701cb0ef41Sopenharmony_ci } else { 1711cb0ef41Sopenharmony_ci name.setTo(description, 0, pos); 1721cb0ef41Sopenharmony_ci while (pos < description.length() && PatternProps::isWhiteSpace(description.charAt(++pos))) { 1731cb0ef41Sopenharmony_ci } 1741cb0ef41Sopenharmony_ci description.remove(0, pos); 1751cb0ef41Sopenharmony_ci } 1761cb0ef41Sopenharmony_ci } else { 1771cb0ef41Sopenharmony_ci name.setTo(UNICODE_STRING_SIMPLE("%default")); 1781cb0ef41Sopenharmony_ci } 1791cb0ef41Sopenharmony_ci 1801cb0ef41Sopenharmony_ci if (description.length() == 0) { 1811cb0ef41Sopenharmony_ci // throw new IllegalArgumentException("Empty rule set description"); 1821cb0ef41Sopenharmony_ci status = U_PARSE_ERROR; 1831cb0ef41Sopenharmony_ci } 1841cb0ef41Sopenharmony_ci 1851cb0ef41Sopenharmony_ci fIsPublic = name.indexOf(gPercentPercent, 2, 0) != 0; 1861cb0ef41Sopenharmony_ci 1871cb0ef41Sopenharmony_ci if ( name.endsWith(gNoparse,8) ) { 1881cb0ef41Sopenharmony_ci fIsParseable = false; 1891cb0ef41Sopenharmony_ci name.truncate(name.length()-8); // remove the @noparse from the name 1901cb0ef41Sopenharmony_ci } 1911cb0ef41Sopenharmony_ci 1921cb0ef41Sopenharmony_ci // all of the other members of NFRuleSet are initialized 1931cb0ef41Sopenharmony_ci // by parseRules() 1941cb0ef41Sopenharmony_ci} 1951cb0ef41Sopenharmony_ci 1961cb0ef41Sopenharmony_civoid 1971cb0ef41Sopenharmony_ciNFRuleSet::parseRules(UnicodeString& description, UErrorCode& status) 1981cb0ef41Sopenharmony_ci{ 1991cb0ef41Sopenharmony_ci // start by creating a Vector whose elements are Strings containing 2001cb0ef41Sopenharmony_ci // the descriptions of the rules (one rule per element). The rules 2011cb0ef41Sopenharmony_ci // are separated by semicolons (there's no escape facility: ALL 2021cb0ef41Sopenharmony_ci // semicolons are rule delimiters) 2031cb0ef41Sopenharmony_ci 2041cb0ef41Sopenharmony_ci if (U_FAILURE(status)) { 2051cb0ef41Sopenharmony_ci return; 2061cb0ef41Sopenharmony_ci } 2071cb0ef41Sopenharmony_ci 2081cb0ef41Sopenharmony_ci // ensure we are starting with an empty rule list 2091cb0ef41Sopenharmony_ci rules.deleteAll(); 2101cb0ef41Sopenharmony_ci 2111cb0ef41Sopenharmony_ci // dlf - the original code kept a separate description array for no reason, 2121cb0ef41Sopenharmony_ci // so I got rid of it. The loop was too complex so I simplified it. 2131cb0ef41Sopenharmony_ci 2141cb0ef41Sopenharmony_ci UnicodeString currentDescription; 2151cb0ef41Sopenharmony_ci int32_t oldP = 0; 2161cb0ef41Sopenharmony_ci while (oldP < description.length()) { 2171cb0ef41Sopenharmony_ci int32_t p = description.indexOf(gSemicolon, oldP); 2181cb0ef41Sopenharmony_ci if (p == -1) { 2191cb0ef41Sopenharmony_ci p = description.length(); 2201cb0ef41Sopenharmony_ci } 2211cb0ef41Sopenharmony_ci currentDescription.setTo(description, oldP, p - oldP); 2221cb0ef41Sopenharmony_ci NFRule::makeRules(currentDescription, this, rules.last(), owner, rules, status); 2231cb0ef41Sopenharmony_ci oldP = p + 1; 2241cb0ef41Sopenharmony_ci } 2251cb0ef41Sopenharmony_ci 2261cb0ef41Sopenharmony_ci // for rules that didn't specify a base value, their base values 2271cb0ef41Sopenharmony_ci // were initialized to 0. Make another pass through the list and 2281cb0ef41Sopenharmony_ci // set all those rules' base values. We also remove any special 2291cb0ef41Sopenharmony_ci // rules from the list and put them into their own member variables 2301cb0ef41Sopenharmony_ci int64_t defaultBaseValue = 0; 2311cb0ef41Sopenharmony_ci 2321cb0ef41Sopenharmony_ci // (this isn't a for loop because we might be deleting items from 2331cb0ef41Sopenharmony_ci // the vector-- we want to make sure we only increment i when 2341cb0ef41Sopenharmony_ci // we _didn't_ delete anything from the vector) 2351cb0ef41Sopenharmony_ci int32_t rulesSize = rules.size(); 2361cb0ef41Sopenharmony_ci for (int32_t i = 0; i < rulesSize; i++) { 2371cb0ef41Sopenharmony_ci NFRule* rule = rules[i]; 2381cb0ef41Sopenharmony_ci int64_t baseValue = rule->getBaseValue(); 2391cb0ef41Sopenharmony_ci 2401cb0ef41Sopenharmony_ci if (baseValue == 0) { 2411cb0ef41Sopenharmony_ci // if the rule's base value is 0, fill in a default 2421cb0ef41Sopenharmony_ci // base value (this will be 1 plus the preceding 2431cb0ef41Sopenharmony_ci // rule's base value for regular rule sets, and the 2441cb0ef41Sopenharmony_ci // same as the preceding rule's base value in fraction 2451cb0ef41Sopenharmony_ci // rule sets) 2461cb0ef41Sopenharmony_ci rule->setBaseValue(defaultBaseValue, status); 2471cb0ef41Sopenharmony_ci } 2481cb0ef41Sopenharmony_ci else { 2491cb0ef41Sopenharmony_ci // if it's a regular rule that already knows its base value, 2501cb0ef41Sopenharmony_ci // check to make sure the rules are in order, and update 2511cb0ef41Sopenharmony_ci // the default base value for the next rule 2521cb0ef41Sopenharmony_ci if (baseValue < defaultBaseValue) { 2531cb0ef41Sopenharmony_ci // throw new IllegalArgumentException("Rules are not in order"); 2541cb0ef41Sopenharmony_ci status = U_PARSE_ERROR; 2551cb0ef41Sopenharmony_ci return; 2561cb0ef41Sopenharmony_ci } 2571cb0ef41Sopenharmony_ci defaultBaseValue = baseValue; 2581cb0ef41Sopenharmony_ci } 2591cb0ef41Sopenharmony_ci if (!fIsFractionRuleSet) { 2601cb0ef41Sopenharmony_ci ++defaultBaseValue; 2611cb0ef41Sopenharmony_ci } 2621cb0ef41Sopenharmony_ci } 2631cb0ef41Sopenharmony_ci} 2641cb0ef41Sopenharmony_ci 2651cb0ef41Sopenharmony_ci/** 2661cb0ef41Sopenharmony_ci * Set one of the non-numerical rules. 2671cb0ef41Sopenharmony_ci * @param rule The rule to set. 2681cb0ef41Sopenharmony_ci */ 2691cb0ef41Sopenharmony_civoid NFRuleSet::setNonNumericalRule(NFRule *rule) { 2701cb0ef41Sopenharmony_ci int64_t baseValue = rule->getBaseValue(); 2711cb0ef41Sopenharmony_ci if (baseValue == NFRule::kNegativeNumberRule) { 2721cb0ef41Sopenharmony_ci delete nonNumericalRules[NEGATIVE_RULE_INDEX]; 2731cb0ef41Sopenharmony_ci nonNumericalRules[NEGATIVE_RULE_INDEX] = rule; 2741cb0ef41Sopenharmony_ci } 2751cb0ef41Sopenharmony_ci else if (baseValue == NFRule::kImproperFractionRule) { 2761cb0ef41Sopenharmony_ci setBestFractionRule(IMPROPER_FRACTION_RULE_INDEX, rule, true); 2771cb0ef41Sopenharmony_ci } 2781cb0ef41Sopenharmony_ci else if (baseValue == NFRule::kProperFractionRule) { 2791cb0ef41Sopenharmony_ci setBestFractionRule(PROPER_FRACTION_RULE_INDEX, rule, true); 2801cb0ef41Sopenharmony_ci } 2811cb0ef41Sopenharmony_ci else if (baseValue == NFRule::kDefaultRule) { 2821cb0ef41Sopenharmony_ci setBestFractionRule(DEFAULT_RULE_INDEX, rule, true); 2831cb0ef41Sopenharmony_ci } 2841cb0ef41Sopenharmony_ci else if (baseValue == NFRule::kInfinityRule) { 2851cb0ef41Sopenharmony_ci delete nonNumericalRules[INFINITY_RULE_INDEX]; 2861cb0ef41Sopenharmony_ci nonNumericalRules[INFINITY_RULE_INDEX] = rule; 2871cb0ef41Sopenharmony_ci } 2881cb0ef41Sopenharmony_ci else if (baseValue == NFRule::kNaNRule) { 2891cb0ef41Sopenharmony_ci delete nonNumericalRules[NAN_RULE_INDEX]; 2901cb0ef41Sopenharmony_ci nonNumericalRules[NAN_RULE_INDEX] = rule; 2911cb0ef41Sopenharmony_ci } 2921cb0ef41Sopenharmony_ci} 2931cb0ef41Sopenharmony_ci 2941cb0ef41Sopenharmony_ci/** 2951cb0ef41Sopenharmony_ci * Determine the best fraction rule to use. Rules matching the decimal point from 2961cb0ef41Sopenharmony_ci * DecimalFormatSymbols become the main set of rules to use. 2971cb0ef41Sopenharmony_ci * @param originalIndex The index into nonNumericalRules 2981cb0ef41Sopenharmony_ci * @param newRule The new rule to consider 2991cb0ef41Sopenharmony_ci * @param rememberRule Should the new rule be added to fractionRules. 3001cb0ef41Sopenharmony_ci */ 3011cb0ef41Sopenharmony_civoid NFRuleSet::setBestFractionRule(int32_t originalIndex, NFRule *newRule, UBool rememberRule) { 3021cb0ef41Sopenharmony_ci if (rememberRule) { 3031cb0ef41Sopenharmony_ci fractionRules.add(newRule); 3041cb0ef41Sopenharmony_ci } 3051cb0ef41Sopenharmony_ci NFRule *bestResult = nonNumericalRules[originalIndex]; 3061cb0ef41Sopenharmony_ci if (bestResult == nullptr) { 3071cb0ef41Sopenharmony_ci nonNumericalRules[originalIndex] = newRule; 3081cb0ef41Sopenharmony_ci } 3091cb0ef41Sopenharmony_ci else { 3101cb0ef41Sopenharmony_ci // We have more than one. Which one is better? 3111cb0ef41Sopenharmony_ci const DecimalFormatSymbols *decimalFormatSymbols = owner->getDecimalFormatSymbols(); 3121cb0ef41Sopenharmony_ci if (decimalFormatSymbols->getSymbol(DecimalFormatSymbols::kDecimalSeparatorSymbol).charAt(0) 3131cb0ef41Sopenharmony_ci == newRule->getDecimalPoint()) 3141cb0ef41Sopenharmony_ci { 3151cb0ef41Sopenharmony_ci nonNumericalRules[originalIndex] = newRule; 3161cb0ef41Sopenharmony_ci } 3171cb0ef41Sopenharmony_ci // else leave it alone 3181cb0ef41Sopenharmony_ci } 3191cb0ef41Sopenharmony_ci} 3201cb0ef41Sopenharmony_ci 3211cb0ef41Sopenharmony_ciNFRuleSet::~NFRuleSet() 3221cb0ef41Sopenharmony_ci{ 3231cb0ef41Sopenharmony_ci for (int i = 0; i < NON_NUMERICAL_RULE_LENGTH; i++) { 3241cb0ef41Sopenharmony_ci if (i != IMPROPER_FRACTION_RULE_INDEX 3251cb0ef41Sopenharmony_ci && i != PROPER_FRACTION_RULE_INDEX 3261cb0ef41Sopenharmony_ci && i != DEFAULT_RULE_INDEX) 3271cb0ef41Sopenharmony_ci { 3281cb0ef41Sopenharmony_ci delete nonNumericalRules[i]; 3291cb0ef41Sopenharmony_ci } 3301cb0ef41Sopenharmony_ci // else it will be deleted via NFRuleList fractionRules 3311cb0ef41Sopenharmony_ci } 3321cb0ef41Sopenharmony_ci} 3331cb0ef41Sopenharmony_ci 3341cb0ef41Sopenharmony_cistatic UBool 3351cb0ef41Sopenharmony_ciutil_equalRules(const NFRule* rule1, const NFRule* rule2) 3361cb0ef41Sopenharmony_ci{ 3371cb0ef41Sopenharmony_ci if (rule1) { 3381cb0ef41Sopenharmony_ci if (rule2) { 3391cb0ef41Sopenharmony_ci return *rule1 == *rule2; 3401cb0ef41Sopenharmony_ci } 3411cb0ef41Sopenharmony_ci } else if (!rule2) { 3421cb0ef41Sopenharmony_ci return true; 3431cb0ef41Sopenharmony_ci } 3441cb0ef41Sopenharmony_ci return false; 3451cb0ef41Sopenharmony_ci} 3461cb0ef41Sopenharmony_ci 3471cb0ef41Sopenharmony_cibool 3481cb0ef41Sopenharmony_ciNFRuleSet::operator==(const NFRuleSet& rhs) const 3491cb0ef41Sopenharmony_ci{ 3501cb0ef41Sopenharmony_ci if (rules.size() == rhs.rules.size() && 3511cb0ef41Sopenharmony_ci fIsFractionRuleSet == rhs.fIsFractionRuleSet && 3521cb0ef41Sopenharmony_ci name == rhs.name) { 3531cb0ef41Sopenharmony_ci 3541cb0ef41Sopenharmony_ci // ...then compare the non-numerical rule lists... 3551cb0ef41Sopenharmony_ci for (int i = 0; i < NON_NUMERICAL_RULE_LENGTH; i++) { 3561cb0ef41Sopenharmony_ci if (!util_equalRules(nonNumericalRules[i], rhs.nonNumericalRules[i])) { 3571cb0ef41Sopenharmony_ci return false; 3581cb0ef41Sopenharmony_ci } 3591cb0ef41Sopenharmony_ci } 3601cb0ef41Sopenharmony_ci 3611cb0ef41Sopenharmony_ci // ...then compare the rule lists... 3621cb0ef41Sopenharmony_ci for (uint32_t i = 0; i < rules.size(); ++i) { 3631cb0ef41Sopenharmony_ci if (*rules[i] != *rhs.rules[i]) { 3641cb0ef41Sopenharmony_ci return false; 3651cb0ef41Sopenharmony_ci } 3661cb0ef41Sopenharmony_ci } 3671cb0ef41Sopenharmony_ci return true; 3681cb0ef41Sopenharmony_ci } 3691cb0ef41Sopenharmony_ci return false; 3701cb0ef41Sopenharmony_ci} 3711cb0ef41Sopenharmony_ci 3721cb0ef41Sopenharmony_civoid 3731cb0ef41Sopenharmony_ciNFRuleSet::setDecimalFormatSymbols(const DecimalFormatSymbols &newSymbols, UErrorCode& status) { 3741cb0ef41Sopenharmony_ci for (uint32_t i = 0; i < rules.size(); ++i) { 3751cb0ef41Sopenharmony_ci rules[i]->setDecimalFormatSymbols(newSymbols, status); 3761cb0ef41Sopenharmony_ci } 3771cb0ef41Sopenharmony_ci // Switch the fraction rules to mirror the DecimalFormatSymbols. 3781cb0ef41Sopenharmony_ci for (int32_t nonNumericalIdx = IMPROPER_FRACTION_RULE_INDEX; nonNumericalIdx <= DEFAULT_RULE_INDEX; nonNumericalIdx++) { 3791cb0ef41Sopenharmony_ci if (nonNumericalRules[nonNumericalIdx]) { 3801cb0ef41Sopenharmony_ci for (uint32_t fIdx = 0; fIdx < fractionRules.size(); fIdx++) { 3811cb0ef41Sopenharmony_ci NFRule *fractionRule = fractionRules[fIdx]; 3821cb0ef41Sopenharmony_ci if (nonNumericalRules[nonNumericalIdx]->getBaseValue() == fractionRule->getBaseValue()) { 3831cb0ef41Sopenharmony_ci setBestFractionRule(nonNumericalIdx, fractionRule, false); 3841cb0ef41Sopenharmony_ci } 3851cb0ef41Sopenharmony_ci } 3861cb0ef41Sopenharmony_ci } 3871cb0ef41Sopenharmony_ci } 3881cb0ef41Sopenharmony_ci 3891cb0ef41Sopenharmony_ci for (uint32_t nnrIdx = 0; nnrIdx < NON_NUMERICAL_RULE_LENGTH; nnrIdx++) { 3901cb0ef41Sopenharmony_ci NFRule *rule = nonNumericalRules[nnrIdx]; 3911cb0ef41Sopenharmony_ci if (rule) { 3921cb0ef41Sopenharmony_ci rule->setDecimalFormatSymbols(newSymbols, status); 3931cb0ef41Sopenharmony_ci } 3941cb0ef41Sopenharmony_ci } 3951cb0ef41Sopenharmony_ci} 3961cb0ef41Sopenharmony_ci 3971cb0ef41Sopenharmony_ci#define RECURSION_LIMIT 64 3981cb0ef41Sopenharmony_ci 3991cb0ef41Sopenharmony_civoid 4001cb0ef41Sopenharmony_ciNFRuleSet::format(int64_t number, UnicodeString& toAppendTo, int32_t pos, int32_t recursionCount, UErrorCode& status) const 4011cb0ef41Sopenharmony_ci{ 4021cb0ef41Sopenharmony_ci if (recursionCount >= RECURSION_LIMIT) { 4031cb0ef41Sopenharmony_ci // stop recursion 4041cb0ef41Sopenharmony_ci status = U_INVALID_STATE_ERROR; 4051cb0ef41Sopenharmony_ci return; 4061cb0ef41Sopenharmony_ci } 4071cb0ef41Sopenharmony_ci const NFRule *rule = findNormalRule(number); 4081cb0ef41Sopenharmony_ci if (rule) { // else error, but can't report it 4091cb0ef41Sopenharmony_ci rule->doFormat(number, toAppendTo, pos, ++recursionCount, status); 4101cb0ef41Sopenharmony_ci } 4111cb0ef41Sopenharmony_ci} 4121cb0ef41Sopenharmony_ci 4131cb0ef41Sopenharmony_civoid 4141cb0ef41Sopenharmony_ciNFRuleSet::format(double number, UnicodeString& toAppendTo, int32_t pos, int32_t recursionCount, UErrorCode& status) const 4151cb0ef41Sopenharmony_ci{ 4161cb0ef41Sopenharmony_ci if (recursionCount >= RECURSION_LIMIT) { 4171cb0ef41Sopenharmony_ci // stop recursion 4181cb0ef41Sopenharmony_ci status = U_INVALID_STATE_ERROR; 4191cb0ef41Sopenharmony_ci return; 4201cb0ef41Sopenharmony_ci } 4211cb0ef41Sopenharmony_ci const NFRule *rule = findDoubleRule(number); 4221cb0ef41Sopenharmony_ci if (rule) { // else error, but can't report it 4231cb0ef41Sopenharmony_ci rule->doFormat(number, toAppendTo, pos, ++recursionCount, status); 4241cb0ef41Sopenharmony_ci } 4251cb0ef41Sopenharmony_ci} 4261cb0ef41Sopenharmony_ci 4271cb0ef41Sopenharmony_ciconst NFRule* 4281cb0ef41Sopenharmony_ciNFRuleSet::findDoubleRule(double number) const 4291cb0ef41Sopenharmony_ci{ 4301cb0ef41Sopenharmony_ci // if this is a fraction rule set, use findFractionRuleSetRule() 4311cb0ef41Sopenharmony_ci if (isFractionRuleSet()) { 4321cb0ef41Sopenharmony_ci return findFractionRuleSetRule(number); 4331cb0ef41Sopenharmony_ci } 4341cb0ef41Sopenharmony_ci 4351cb0ef41Sopenharmony_ci if (uprv_isNaN(number)) { 4361cb0ef41Sopenharmony_ci const NFRule *rule = nonNumericalRules[NAN_RULE_INDEX]; 4371cb0ef41Sopenharmony_ci if (!rule) { 4381cb0ef41Sopenharmony_ci rule = owner->getDefaultNaNRule(); 4391cb0ef41Sopenharmony_ci } 4401cb0ef41Sopenharmony_ci return rule; 4411cb0ef41Sopenharmony_ci } 4421cb0ef41Sopenharmony_ci 4431cb0ef41Sopenharmony_ci // if the number is negative, return the negative number rule 4441cb0ef41Sopenharmony_ci // (if there isn't a negative-number rule, we pretend it's a 4451cb0ef41Sopenharmony_ci // positive number) 4461cb0ef41Sopenharmony_ci if (number < 0) { 4471cb0ef41Sopenharmony_ci if (nonNumericalRules[NEGATIVE_RULE_INDEX]) { 4481cb0ef41Sopenharmony_ci return nonNumericalRules[NEGATIVE_RULE_INDEX]; 4491cb0ef41Sopenharmony_ci } else { 4501cb0ef41Sopenharmony_ci number = -number; 4511cb0ef41Sopenharmony_ci } 4521cb0ef41Sopenharmony_ci } 4531cb0ef41Sopenharmony_ci 4541cb0ef41Sopenharmony_ci if (uprv_isInfinite(number)) { 4551cb0ef41Sopenharmony_ci const NFRule *rule = nonNumericalRules[INFINITY_RULE_INDEX]; 4561cb0ef41Sopenharmony_ci if (!rule) { 4571cb0ef41Sopenharmony_ci rule = owner->getDefaultInfinityRule(); 4581cb0ef41Sopenharmony_ci } 4591cb0ef41Sopenharmony_ci return rule; 4601cb0ef41Sopenharmony_ci } 4611cb0ef41Sopenharmony_ci 4621cb0ef41Sopenharmony_ci // if the number isn't an integer, we use one of the fraction rules... 4631cb0ef41Sopenharmony_ci if (number != uprv_floor(number)) { 4641cb0ef41Sopenharmony_ci // if the number is between 0 and 1, return the proper 4651cb0ef41Sopenharmony_ci // fraction rule 4661cb0ef41Sopenharmony_ci if (number < 1 && nonNumericalRules[PROPER_FRACTION_RULE_INDEX]) { 4671cb0ef41Sopenharmony_ci return nonNumericalRules[PROPER_FRACTION_RULE_INDEX]; 4681cb0ef41Sopenharmony_ci } 4691cb0ef41Sopenharmony_ci // otherwise, return the improper fraction rule 4701cb0ef41Sopenharmony_ci else if (nonNumericalRules[IMPROPER_FRACTION_RULE_INDEX]) { 4711cb0ef41Sopenharmony_ci return nonNumericalRules[IMPROPER_FRACTION_RULE_INDEX]; 4721cb0ef41Sopenharmony_ci } 4731cb0ef41Sopenharmony_ci } 4741cb0ef41Sopenharmony_ci 4751cb0ef41Sopenharmony_ci // if there's a default rule, use it to format the number 4761cb0ef41Sopenharmony_ci if (nonNumericalRules[DEFAULT_RULE_INDEX]) { 4771cb0ef41Sopenharmony_ci return nonNumericalRules[DEFAULT_RULE_INDEX]; 4781cb0ef41Sopenharmony_ci } 4791cb0ef41Sopenharmony_ci 4801cb0ef41Sopenharmony_ci // and if we haven't yet returned a rule, use findNormalRule() 4811cb0ef41Sopenharmony_ci // to find the applicable rule 4821cb0ef41Sopenharmony_ci int64_t r = util64_fromDouble(number + 0.5); 4831cb0ef41Sopenharmony_ci return findNormalRule(r); 4841cb0ef41Sopenharmony_ci} 4851cb0ef41Sopenharmony_ci 4861cb0ef41Sopenharmony_ciconst NFRule * 4871cb0ef41Sopenharmony_ciNFRuleSet::findNormalRule(int64_t number) const 4881cb0ef41Sopenharmony_ci{ 4891cb0ef41Sopenharmony_ci // if this is a fraction rule set, use findFractionRuleSetRule() 4901cb0ef41Sopenharmony_ci // to find the rule (we should only go into this clause if the 4911cb0ef41Sopenharmony_ci // value is 0) 4921cb0ef41Sopenharmony_ci if (fIsFractionRuleSet) { 4931cb0ef41Sopenharmony_ci return findFractionRuleSetRule((double)number); 4941cb0ef41Sopenharmony_ci } 4951cb0ef41Sopenharmony_ci 4961cb0ef41Sopenharmony_ci // if the number is negative, return the negative-number rule 4971cb0ef41Sopenharmony_ci // (if there isn't one, pretend the number is positive) 4981cb0ef41Sopenharmony_ci if (number < 0) { 4991cb0ef41Sopenharmony_ci if (nonNumericalRules[NEGATIVE_RULE_INDEX]) { 5001cb0ef41Sopenharmony_ci return nonNumericalRules[NEGATIVE_RULE_INDEX]; 5011cb0ef41Sopenharmony_ci } else { 5021cb0ef41Sopenharmony_ci number = -number; 5031cb0ef41Sopenharmony_ci } 5041cb0ef41Sopenharmony_ci } 5051cb0ef41Sopenharmony_ci 5061cb0ef41Sopenharmony_ci // we have to repeat the preceding two checks, even though we 5071cb0ef41Sopenharmony_ci // do them in findRule(), because the version of format() that 5081cb0ef41Sopenharmony_ci // takes a long bypasses findRule() and goes straight to this 5091cb0ef41Sopenharmony_ci // function. This function does skip the fraction rules since 5101cb0ef41Sopenharmony_ci // we know the value is an integer (it also skips the default 5111cb0ef41Sopenharmony_ci // rule, since it's considered a fraction rule. Skipping the 5121cb0ef41Sopenharmony_ci // default rule in this function is also how we avoid infinite 5131cb0ef41Sopenharmony_ci // recursion) 5141cb0ef41Sopenharmony_ci 5151cb0ef41Sopenharmony_ci // {dlf} unfortunately this fails if there are no rules except 5161cb0ef41Sopenharmony_ci // special rules. If there are no rules, use the default rule. 5171cb0ef41Sopenharmony_ci 5181cb0ef41Sopenharmony_ci // binary-search the rule list for the applicable rule 5191cb0ef41Sopenharmony_ci // (a rule is used for all values from its base value to 5201cb0ef41Sopenharmony_ci // the next rule's base value) 5211cb0ef41Sopenharmony_ci int32_t hi = rules.size(); 5221cb0ef41Sopenharmony_ci if (hi > 0) { 5231cb0ef41Sopenharmony_ci int32_t lo = 0; 5241cb0ef41Sopenharmony_ci 5251cb0ef41Sopenharmony_ci while (lo < hi) { 5261cb0ef41Sopenharmony_ci int32_t mid = (lo + hi) / 2; 5271cb0ef41Sopenharmony_ci if (rules[mid]->getBaseValue() == number) { 5281cb0ef41Sopenharmony_ci return rules[mid]; 5291cb0ef41Sopenharmony_ci } 5301cb0ef41Sopenharmony_ci else if (rules[mid]->getBaseValue() > number) { 5311cb0ef41Sopenharmony_ci hi = mid; 5321cb0ef41Sopenharmony_ci } 5331cb0ef41Sopenharmony_ci else { 5341cb0ef41Sopenharmony_ci lo = mid + 1; 5351cb0ef41Sopenharmony_ci } 5361cb0ef41Sopenharmony_ci } 5371cb0ef41Sopenharmony_ci if (hi == 0) { // bad rule set, minimum base > 0 5381cb0ef41Sopenharmony_ci return nullptr; // want to throw exception here 5391cb0ef41Sopenharmony_ci } 5401cb0ef41Sopenharmony_ci 5411cb0ef41Sopenharmony_ci NFRule *result = rules[hi - 1]; 5421cb0ef41Sopenharmony_ci 5431cb0ef41Sopenharmony_ci // use shouldRollBack() to see whether we need to invoke the 5441cb0ef41Sopenharmony_ci // rollback rule (see shouldRollBack()'s documentation for 5451cb0ef41Sopenharmony_ci // an explanation of the rollback rule). If we do, roll back 5461cb0ef41Sopenharmony_ci // one rule and return that one instead of the one we'd normally 5471cb0ef41Sopenharmony_ci // return 5481cb0ef41Sopenharmony_ci if (result->shouldRollBack(number)) { 5491cb0ef41Sopenharmony_ci if (hi == 1) { // bad rule set, no prior rule to rollback to from this base 5501cb0ef41Sopenharmony_ci return nullptr; 5511cb0ef41Sopenharmony_ci } 5521cb0ef41Sopenharmony_ci result = rules[hi - 2]; 5531cb0ef41Sopenharmony_ci } 5541cb0ef41Sopenharmony_ci return result; 5551cb0ef41Sopenharmony_ci } 5561cb0ef41Sopenharmony_ci // else use the default rule 5571cb0ef41Sopenharmony_ci return nonNumericalRules[DEFAULT_RULE_INDEX]; 5581cb0ef41Sopenharmony_ci} 5591cb0ef41Sopenharmony_ci 5601cb0ef41Sopenharmony_ci/** 5611cb0ef41Sopenharmony_ci * If this rule is a fraction rule set, this function is used by 5621cb0ef41Sopenharmony_ci * findRule() to select the most appropriate rule for formatting 5631cb0ef41Sopenharmony_ci * the number. Basically, the base value of each rule in the rule 5641cb0ef41Sopenharmony_ci * set is treated as the denominator of a fraction. Whichever 5651cb0ef41Sopenharmony_ci * denominator can produce the fraction closest in value to the 5661cb0ef41Sopenharmony_ci * number passed in is the result. If there's a tie, the earlier 5671cb0ef41Sopenharmony_ci * one in the list wins. (If there are two rules in a row with the 5681cb0ef41Sopenharmony_ci * same base value, the first one is used when the numerator of the 5691cb0ef41Sopenharmony_ci * fraction would be 1, and the second rule is used the rest of the 5701cb0ef41Sopenharmony_ci * time. 5711cb0ef41Sopenharmony_ci * @param number The number being formatted (which will always be 5721cb0ef41Sopenharmony_ci * a number between 0 and 1) 5731cb0ef41Sopenharmony_ci * @return The rule to use to format this number 5741cb0ef41Sopenharmony_ci */ 5751cb0ef41Sopenharmony_ciconst NFRule* 5761cb0ef41Sopenharmony_ciNFRuleSet::findFractionRuleSetRule(double number) const 5771cb0ef41Sopenharmony_ci{ 5781cb0ef41Sopenharmony_ci // the obvious way to do this (multiply the value being formatted 5791cb0ef41Sopenharmony_ci // by each rule's base value until you get an integral result) 5801cb0ef41Sopenharmony_ci // doesn't work because of rounding error. This method is more 5811cb0ef41Sopenharmony_ci // accurate 5821cb0ef41Sopenharmony_ci 5831cb0ef41Sopenharmony_ci // find the least common multiple of the rules' base values 5841cb0ef41Sopenharmony_ci // and multiply this by the number being formatted. This is 5851cb0ef41Sopenharmony_ci // all the precision we need, and we can do all of the rest 5861cb0ef41Sopenharmony_ci // of the math using integer arithmetic 5871cb0ef41Sopenharmony_ci int64_t leastCommonMultiple = rules[0]->getBaseValue(); 5881cb0ef41Sopenharmony_ci int64_t numerator; 5891cb0ef41Sopenharmony_ci { 5901cb0ef41Sopenharmony_ci for (uint32_t i = 1; i < rules.size(); ++i) { 5911cb0ef41Sopenharmony_ci leastCommonMultiple = util_lcm(leastCommonMultiple, rules[i]->getBaseValue()); 5921cb0ef41Sopenharmony_ci } 5931cb0ef41Sopenharmony_ci numerator = util64_fromDouble(number * (double)leastCommonMultiple + 0.5); 5941cb0ef41Sopenharmony_ci } 5951cb0ef41Sopenharmony_ci // for each rule, do the following... 5961cb0ef41Sopenharmony_ci int64_t tempDifference; 5971cb0ef41Sopenharmony_ci int64_t difference = util64_fromDouble(uprv_maxMantissa()); 5981cb0ef41Sopenharmony_ci int32_t winner = 0; 5991cb0ef41Sopenharmony_ci for (uint32_t i = 0; i < rules.size(); ++i) { 6001cb0ef41Sopenharmony_ci // "numerator" is the numerator of the fraction if the 6011cb0ef41Sopenharmony_ci // denominator is the LCD. The numerator if the rule's 6021cb0ef41Sopenharmony_ci // base value is the denominator is "numerator" times the 6031cb0ef41Sopenharmony_ci // base value divided bythe LCD. Here we check to see if 6041cb0ef41Sopenharmony_ci // that's an integer, and if not, how close it is to being 6051cb0ef41Sopenharmony_ci // an integer. 6061cb0ef41Sopenharmony_ci tempDifference = numerator * rules[i]->getBaseValue() % leastCommonMultiple; 6071cb0ef41Sopenharmony_ci 6081cb0ef41Sopenharmony_ci 6091cb0ef41Sopenharmony_ci // normalize the result of the above calculation: we want 6101cb0ef41Sopenharmony_ci // the numerator's distance from the CLOSEST multiple 6111cb0ef41Sopenharmony_ci // of the LCD 6121cb0ef41Sopenharmony_ci if (leastCommonMultiple - tempDifference < tempDifference) { 6131cb0ef41Sopenharmony_ci tempDifference = leastCommonMultiple - tempDifference; 6141cb0ef41Sopenharmony_ci } 6151cb0ef41Sopenharmony_ci 6161cb0ef41Sopenharmony_ci // if this is as close as we've come, keep track of how close 6171cb0ef41Sopenharmony_ci // that is, and the line number of the rule that did it. If 6181cb0ef41Sopenharmony_ci // we've scored a direct hit, we don't have to look at any more 6191cb0ef41Sopenharmony_ci // rules 6201cb0ef41Sopenharmony_ci if (tempDifference < difference) { 6211cb0ef41Sopenharmony_ci difference = tempDifference; 6221cb0ef41Sopenharmony_ci winner = i; 6231cb0ef41Sopenharmony_ci if (difference == 0) { 6241cb0ef41Sopenharmony_ci break; 6251cb0ef41Sopenharmony_ci } 6261cb0ef41Sopenharmony_ci } 6271cb0ef41Sopenharmony_ci } 6281cb0ef41Sopenharmony_ci 6291cb0ef41Sopenharmony_ci // if we have two successive rules that both have the winning base 6301cb0ef41Sopenharmony_ci // value, then the first one (the one we found above) is used if 6311cb0ef41Sopenharmony_ci // the numerator of the fraction is 1 and the second one is used if 6321cb0ef41Sopenharmony_ci // the numerator of the fraction is anything else (this lets us 6331cb0ef41Sopenharmony_ci // do things like "one third"/"two thirds" without having to define 6341cb0ef41Sopenharmony_ci // a whole bunch of extra rule sets) 6351cb0ef41Sopenharmony_ci if ((unsigned)(winner + 1) < rules.size() && 6361cb0ef41Sopenharmony_ci rules[winner + 1]->getBaseValue() == rules[winner]->getBaseValue()) { 6371cb0ef41Sopenharmony_ci double n = ((double)rules[winner]->getBaseValue()) * number; 6381cb0ef41Sopenharmony_ci if (n < 0.5 || n >= 2) { 6391cb0ef41Sopenharmony_ci ++winner; 6401cb0ef41Sopenharmony_ci } 6411cb0ef41Sopenharmony_ci } 6421cb0ef41Sopenharmony_ci 6431cb0ef41Sopenharmony_ci // finally, return the winning rule 6441cb0ef41Sopenharmony_ci return rules[winner]; 6451cb0ef41Sopenharmony_ci} 6461cb0ef41Sopenharmony_ci 6471cb0ef41Sopenharmony_ci/** 6481cb0ef41Sopenharmony_ci * Parses a string. Matches the string to be parsed against each 6491cb0ef41Sopenharmony_ci * of its rules (with a base value less than upperBound) and returns 6501cb0ef41Sopenharmony_ci * the value produced by the rule that matched the most characters 6511cb0ef41Sopenharmony_ci * in the source string. 6521cb0ef41Sopenharmony_ci * @param text The string to parse 6531cb0ef41Sopenharmony_ci * @param parsePosition The initial position is ignored and assumed 6541cb0ef41Sopenharmony_ci * to be 0. On exit, this object has been updated to point to the 6551cb0ef41Sopenharmony_ci * first character position this rule set didn't consume. 6561cb0ef41Sopenharmony_ci * @param upperBound Limits the rules that can be allowed to match. 6571cb0ef41Sopenharmony_ci * Only rules whose base values are strictly less than upperBound 6581cb0ef41Sopenharmony_ci * are considered. 6591cb0ef41Sopenharmony_ci * @return The numerical result of parsing this string. This will 6601cb0ef41Sopenharmony_ci * be the matching rule's base value, composed appropriately with 6611cb0ef41Sopenharmony_ci * the results of matching any of its substitutions. The object 6621cb0ef41Sopenharmony_ci * will be an instance of Long if it's an integral value; otherwise, 6631cb0ef41Sopenharmony_ci * it will be an instance of Double. This function always returns 6641cb0ef41Sopenharmony_ci * a valid object: If nothing matched the input string at all, 6651cb0ef41Sopenharmony_ci * this function returns new Long(0), and the parse position is 6661cb0ef41Sopenharmony_ci * left unchanged. 6671cb0ef41Sopenharmony_ci */ 6681cb0ef41Sopenharmony_ci#ifdef RBNF_DEBUG 6691cb0ef41Sopenharmony_ci#include <stdio.h> 6701cb0ef41Sopenharmony_ci 6711cb0ef41Sopenharmony_cistatic void dumpUS(FILE* f, const UnicodeString& us) { 6721cb0ef41Sopenharmony_ci int len = us.length(); 6731cb0ef41Sopenharmony_ci char* buf = (char *)uprv_malloc((len+1)*sizeof(char)); //new char[len+1]; 6741cb0ef41Sopenharmony_ci if (buf != nullptr) { 6751cb0ef41Sopenharmony_ci us.extract(0, len, buf); 6761cb0ef41Sopenharmony_ci buf[len] = 0; 6771cb0ef41Sopenharmony_ci fprintf(f, "%s", buf); 6781cb0ef41Sopenharmony_ci uprv_free(buf); //delete[] buf; 6791cb0ef41Sopenharmony_ci } 6801cb0ef41Sopenharmony_ci} 6811cb0ef41Sopenharmony_ci#endif 6821cb0ef41Sopenharmony_ci 6831cb0ef41Sopenharmony_ciUBool 6841cb0ef41Sopenharmony_ciNFRuleSet::parse(const UnicodeString& text, ParsePosition& pos, double upperBound, uint32_t nonNumericalExecutedRuleMask, Formattable& result) const 6851cb0ef41Sopenharmony_ci{ 6861cb0ef41Sopenharmony_ci // try matching each rule in the rule set against the text being 6871cb0ef41Sopenharmony_ci // parsed. Whichever one matches the most characters is the one 6881cb0ef41Sopenharmony_ci // that determines the value we return. 6891cb0ef41Sopenharmony_ci 6901cb0ef41Sopenharmony_ci result.setLong(0); 6911cb0ef41Sopenharmony_ci 6921cb0ef41Sopenharmony_ci // dump out if there's no text to parse 6931cb0ef41Sopenharmony_ci if (text.length() == 0) { 6941cb0ef41Sopenharmony_ci return 0; 6951cb0ef41Sopenharmony_ci } 6961cb0ef41Sopenharmony_ci 6971cb0ef41Sopenharmony_ci ParsePosition highWaterMark; 6981cb0ef41Sopenharmony_ci ParsePosition workingPos = pos; 6991cb0ef41Sopenharmony_ci 7001cb0ef41Sopenharmony_ci#ifdef RBNF_DEBUG 7011cb0ef41Sopenharmony_ci fprintf(stderr, "<nfrs> %x '", this); 7021cb0ef41Sopenharmony_ci dumpUS(stderr, name); 7031cb0ef41Sopenharmony_ci fprintf(stderr, "' text '"); 7041cb0ef41Sopenharmony_ci dumpUS(stderr, text); 7051cb0ef41Sopenharmony_ci fprintf(stderr, "'\n"); 7061cb0ef41Sopenharmony_ci fprintf(stderr, " parse negative: %d\n", this, negativeNumberRule != 0); 7071cb0ef41Sopenharmony_ci#endif 7081cb0ef41Sopenharmony_ci // Try each of the negative rules, fraction rules, infinity rules and NaN rules 7091cb0ef41Sopenharmony_ci for (int i = 0; i < NON_NUMERICAL_RULE_LENGTH; i++) { 7101cb0ef41Sopenharmony_ci if (nonNumericalRules[i] && ((nonNumericalExecutedRuleMask >> i) & 1) == 0) { 7111cb0ef41Sopenharmony_ci // Mark this rule as being executed so that we don't try to execute it again. 7121cb0ef41Sopenharmony_ci nonNumericalExecutedRuleMask |= 1 << i; 7131cb0ef41Sopenharmony_ci 7141cb0ef41Sopenharmony_ci Formattable tempResult; 7151cb0ef41Sopenharmony_ci UBool success = nonNumericalRules[i]->doParse(text, workingPos, 0, upperBound, nonNumericalExecutedRuleMask, tempResult); 7161cb0ef41Sopenharmony_ci if (success && (workingPos.getIndex() > highWaterMark.getIndex())) { 7171cb0ef41Sopenharmony_ci result = tempResult; 7181cb0ef41Sopenharmony_ci highWaterMark = workingPos; 7191cb0ef41Sopenharmony_ci } 7201cb0ef41Sopenharmony_ci workingPos = pos; 7211cb0ef41Sopenharmony_ci } 7221cb0ef41Sopenharmony_ci } 7231cb0ef41Sopenharmony_ci#ifdef RBNF_DEBUG 7241cb0ef41Sopenharmony_ci fprintf(stderr, "<nfrs> continue other with text '"); 7251cb0ef41Sopenharmony_ci dumpUS(stderr, text); 7261cb0ef41Sopenharmony_ci fprintf(stderr, "' hwm: %d\n", highWaterMark.getIndex()); 7271cb0ef41Sopenharmony_ci#endif 7281cb0ef41Sopenharmony_ci 7291cb0ef41Sopenharmony_ci // finally, go through the regular rules one at a time. We start 7301cb0ef41Sopenharmony_ci // at the end of the list because we want to try matching the most 7311cb0ef41Sopenharmony_ci // sigificant rule first (this helps ensure that we parse 7321cb0ef41Sopenharmony_ci // "five thousand three hundred six" as 7331cb0ef41Sopenharmony_ci // "(five thousand) (three hundred) (six)" rather than 7341cb0ef41Sopenharmony_ci // "((five thousand three) hundred) (six)"). Skip rules whose 7351cb0ef41Sopenharmony_ci // base values are higher than the upper bound (again, this helps 7361cb0ef41Sopenharmony_ci // limit ambiguity by making sure the rules that match a rule's 7371cb0ef41Sopenharmony_ci // are less significant than the rule containing the substitutions)/ 7381cb0ef41Sopenharmony_ci { 7391cb0ef41Sopenharmony_ci int64_t ub = util64_fromDouble(upperBound); 7401cb0ef41Sopenharmony_ci#ifdef RBNF_DEBUG 7411cb0ef41Sopenharmony_ci { 7421cb0ef41Sopenharmony_ci char ubstr[64]; 7431cb0ef41Sopenharmony_ci util64_toa(ub, ubstr, 64); 7441cb0ef41Sopenharmony_ci char ubstrhex[64]; 7451cb0ef41Sopenharmony_ci util64_toa(ub, ubstrhex, 64, 16); 7461cb0ef41Sopenharmony_ci fprintf(stderr, "ub: %g, i64: %s (%s)\n", upperBound, ubstr, ubstrhex); 7471cb0ef41Sopenharmony_ci } 7481cb0ef41Sopenharmony_ci#endif 7491cb0ef41Sopenharmony_ci for (int32_t i = rules.size(); --i >= 0 && highWaterMark.getIndex() < text.length();) { 7501cb0ef41Sopenharmony_ci if ((!fIsFractionRuleSet) && (rules[i]->getBaseValue() >= ub)) { 7511cb0ef41Sopenharmony_ci continue; 7521cb0ef41Sopenharmony_ci } 7531cb0ef41Sopenharmony_ci Formattable tempResult; 7541cb0ef41Sopenharmony_ci UBool success = rules[i]->doParse(text, workingPos, fIsFractionRuleSet, upperBound, nonNumericalExecutedRuleMask, tempResult); 7551cb0ef41Sopenharmony_ci if (success && workingPos.getIndex() > highWaterMark.getIndex()) { 7561cb0ef41Sopenharmony_ci result = tempResult; 7571cb0ef41Sopenharmony_ci highWaterMark = workingPos; 7581cb0ef41Sopenharmony_ci } 7591cb0ef41Sopenharmony_ci workingPos = pos; 7601cb0ef41Sopenharmony_ci } 7611cb0ef41Sopenharmony_ci } 7621cb0ef41Sopenharmony_ci#ifdef RBNF_DEBUG 7631cb0ef41Sopenharmony_ci fprintf(stderr, "<nfrs> exit\n"); 7641cb0ef41Sopenharmony_ci#endif 7651cb0ef41Sopenharmony_ci // finally, update the parse position we were passed to point to the 7661cb0ef41Sopenharmony_ci // first character we didn't use, and return the result that 7671cb0ef41Sopenharmony_ci // corresponds to that string of characters 7681cb0ef41Sopenharmony_ci pos = highWaterMark; 7691cb0ef41Sopenharmony_ci 7701cb0ef41Sopenharmony_ci return 1; 7711cb0ef41Sopenharmony_ci} 7721cb0ef41Sopenharmony_ci 7731cb0ef41Sopenharmony_civoid 7741cb0ef41Sopenharmony_ciNFRuleSet::appendRules(UnicodeString& result) const 7751cb0ef41Sopenharmony_ci{ 7761cb0ef41Sopenharmony_ci uint32_t i; 7771cb0ef41Sopenharmony_ci 7781cb0ef41Sopenharmony_ci // the rule set name goes first... 7791cb0ef41Sopenharmony_ci result.append(name); 7801cb0ef41Sopenharmony_ci result.append(gColon); 7811cb0ef41Sopenharmony_ci result.append(gLineFeed); 7821cb0ef41Sopenharmony_ci 7831cb0ef41Sopenharmony_ci // followed by the regular rules... 7841cb0ef41Sopenharmony_ci for (i = 0; i < rules.size(); i++) { 7851cb0ef41Sopenharmony_ci rules[i]->_appendRuleText(result); 7861cb0ef41Sopenharmony_ci result.append(gLineFeed); 7871cb0ef41Sopenharmony_ci } 7881cb0ef41Sopenharmony_ci 7891cb0ef41Sopenharmony_ci // followed by the special rules (if they exist) 7901cb0ef41Sopenharmony_ci for (i = 0; i < NON_NUMERICAL_RULE_LENGTH; ++i) { 7911cb0ef41Sopenharmony_ci NFRule *rule = nonNumericalRules[i]; 7921cb0ef41Sopenharmony_ci if (nonNumericalRules[i]) { 7931cb0ef41Sopenharmony_ci if (rule->getBaseValue() == NFRule::kImproperFractionRule 7941cb0ef41Sopenharmony_ci || rule->getBaseValue() == NFRule::kProperFractionRule 7951cb0ef41Sopenharmony_ci || rule->getBaseValue() == NFRule::kDefaultRule) 7961cb0ef41Sopenharmony_ci { 7971cb0ef41Sopenharmony_ci for (uint32_t fIdx = 0; fIdx < fractionRules.size(); fIdx++) { 7981cb0ef41Sopenharmony_ci NFRule *fractionRule = fractionRules[fIdx]; 7991cb0ef41Sopenharmony_ci if (fractionRule->getBaseValue() == rule->getBaseValue()) { 8001cb0ef41Sopenharmony_ci fractionRule->_appendRuleText(result); 8011cb0ef41Sopenharmony_ci result.append(gLineFeed); 8021cb0ef41Sopenharmony_ci } 8031cb0ef41Sopenharmony_ci } 8041cb0ef41Sopenharmony_ci } 8051cb0ef41Sopenharmony_ci else { 8061cb0ef41Sopenharmony_ci rule->_appendRuleText(result); 8071cb0ef41Sopenharmony_ci result.append(gLineFeed); 8081cb0ef41Sopenharmony_ci } 8091cb0ef41Sopenharmony_ci } 8101cb0ef41Sopenharmony_ci } 8111cb0ef41Sopenharmony_ci} 8121cb0ef41Sopenharmony_ci 8131cb0ef41Sopenharmony_ci// utility functions 8141cb0ef41Sopenharmony_ci 8151cb0ef41Sopenharmony_ciint64_t util64_fromDouble(double d) { 8161cb0ef41Sopenharmony_ci int64_t result = 0; 8171cb0ef41Sopenharmony_ci if (!uprv_isNaN(d)) { 8181cb0ef41Sopenharmony_ci double mant = uprv_maxMantissa(); 8191cb0ef41Sopenharmony_ci if (d < -mant) { 8201cb0ef41Sopenharmony_ci d = -mant; 8211cb0ef41Sopenharmony_ci } else if (d > mant) { 8221cb0ef41Sopenharmony_ci d = mant; 8231cb0ef41Sopenharmony_ci } 8241cb0ef41Sopenharmony_ci UBool neg = d < 0; 8251cb0ef41Sopenharmony_ci if (neg) { 8261cb0ef41Sopenharmony_ci d = -d; 8271cb0ef41Sopenharmony_ci } 8281cb0ef41Sopenharmony_ci result = (int64_t)uprv_floor(d); 8291cb0ef41Sopenharmony_ci if (neg) { 8301cb0ef41Sopenharmony_ci result = -result; 8311cb0ef41Sopenharmony_ci } 8321cb0ef41Sopenharmony_ci } 8331cb0ef41Sopenharmony_ci return result; 8341cb0ef41Sopenharmony_ci} 8351cb0ef41Sopenharmony_ci 8361cb0ef41Sopenharmony_ciuint64_t util64_pow(uint32_t base, uint16_t exponent) { 8371cb0ef41Sopenharmony_ci if (base == 0) { 8381cb0ef41Sopenharmony_ci return 0; 8391cb0ef41Sopenharmony_ci } 8401cb0ef41Sopenharmony_ci uint64_t result = 1; 8411cb0ef41Sopenharmony_ci uint64_t pow = base; 8421cb0ef41Sopenharmony_ci while (true) { 8431cb0ef41Sopenharmony_ci if ((exponent & 1) == 1) { 8441cb0ef41Sopenharmony_ci result *= pow; 8451cb0ef41Sopenharmony_ci } 8461cb0ef41Sopenharmony_ci exponent >>= 1; 8471cb0ef41Sopenharmony_ci if (exponent == 0) { 8481cb0ef41Sopenharmony_ci break; 8491cb0ef41Sopenharmony_ci } 8501cb0ef41Sopenharmony_ci pow *= pow; 8511cb0ef41Sopenharmony_ci } 8521cb0ef41Sopenharmony_ci return result; 8531cb0ef41Sopenharmony_ci} 8541cb0ef41Sopenharmony_ci 8551cb0ef41Sopenharmony_cistatic const uint8_t asciiDigits[] = { 8561cb0ef41Sopenharmony_ci 0x30u, 0x31u, 0x32u, 0x33u, 0x34u, 0x35u, 0x36u, 0x37u, 8571cb0ef41Sopenharmony_ci 0x38u, 0x39u, 0x61u, 0x62u, 0x63u, 0x64u, 0x65u, 0x66u, 8581cb0ef41Sopenharmony_ci 0x67u, 0x68u, 0x69u, 0x6au, 0x6bu, 0x6cu, 0x6du, 0x6eu, 8591cb0ef41Sopenharmony_ci 0x6fu, 0x70u, 0x71u, 0x72u, 0x73u, 0x74u, 0x75u, 0x76u, 8601cb0ef41Sopenharmony_ci 0x77u, 0x78u, 0x79u, 0x7au, 8611cb0ef41Sopenharmony_ci}; 8621cb0ef41Sopenharmony_ci 8631cb0ef41Sopenharmony_cistatic const char16_t kUMinus = (char16_t)0x002d; 8641cb0ef41Sopenharmony_ci 8651cb0ef41Sopenharmony_ci#ifdef RBNF_DEBUG 8661cb0ef41Sopenharmony_cistatic const char kMinus = '-'; 8671cb0ef41Sopenharmony_ci 8681cb0ef41Sopenharmony_cistatic const uint8_t digitInfo[] = { 8691cb0ef41Sopenharmony_ci 0, 0, 0, 0, 0, 0, 0, 0, 8701cb0ef41Sopenharmony_ci 0, 0, 0, 0, 0, 0, 0, 0, 8711cb0ef41Sopenharmony_ci 0, 0, 0, 0, 0, 0, 0, 0, 8721cb0ef41Sopenharmony_ci 0, 0, 0, 0, 0, 0, 0, 0, 8731cb0ef41Sopenharmony_ci 0, 0, 0, 0, 0, 0, 0, 0, 8741cb0ef41Sopenharmony_ci 0, 0, 0, 0, 0, 0, 0, 0, 8751cb0ef41Sopenharmony_ci 0x80u, 0x81u, 0x82u, 0x83u, 0x84u, 0x85u, 0x86u, 0x87u, 8761cb0ef41Sopenharmony_ci 0x88u, 0x89u, 0, 0, 0, 0, 0, 0, 8771cb0ef41Sopenharmony_ci 0, 0x8au, 0x8bu, 0x8cu, 0x8du, 0x8eu, 0x8fu, 0x90u, 8781cb0ef41Sopenharmony_ci 0x91u, 0x92u, 0x93u, 0x94u, 0x95u, 0x96u, 0x97u, 0x98u, 8791cb0ef41Sopenharmony_ci 0x99u, 0x9au, 0x9bu, 0x9cu, 0x9du, 0x9eu, 0x9fu, 0xa0u, 8801cb0ef41Sopenharmony_ci 0xa1u, 0xa2u, 0xa3u, 0, 0, 0, 0, 0, 8811cb0ef41Sopenharmony_ci 0, 0x8au, 0x8bu, 0x8cu, 0x8du, 0x8eu, 0x8fu, 0x90u, 8821cb0ef41Sopenharmony_ci 0x91u, 0x92u, 0x93u, 0x94u, 0x95u, 0x96u, 0x97u, 0x98u, 8831cb0ef41Sopenharmony_ci 0x99u, 0x9au, 0x9bu, 0x9cu, 0x9du, 0x9eu, 0x9fu, 0xa0u, 8841cb0ef41Sopenharmony_ci 0xa1u, 0xa2u, 0xa3u, 0, 0, 0, 0, 0, 8851cb0ef41Sopenharmony_ci}; 8861cb0ef41Sopenharmony_ci 8871cb0ef41Sopenharmony_ciint64_t util64_atoi(const char* str, uint32_t radix) 8881cb0ef41Sopenharmony_ci{ 8891cb0ef41Sopenharmony_ci if (radix > 36) { 8901cb0ef41Sopenharmony_ci radix = 36; 8911cb0ef41Sopenharmony_ci } else if (radix < 2) { 8921cb0ef41Sopenharmony_ci radix = 2; 8931cb0ef41Sopenharmony_ci } 8941cb0ef41Sopenharmony_ci int64_t lradix = radix; 8951cb0ef41Sopenharmony_ci 8961cb0ef41Sopenharmony_ci int neg = 0; 8971cb0ef41Sopenharmony_ci if (*str == kMinus) { 8981cb0ef41Sopenharmony_ci ++str; 8991cb0ef41Sopenharmony_ci neg = 1; 9001cb0ef41Sopenharmony_ci } 9011cb0ef41Sopenharmony_ci int64_t result = 0; 9021cb0ef41Sopenharmony_ci uint8_t b; 9031cb0ef41Sopenharmony_ci while ((b = digitInfo[*str++]) && ((b &= 0x7f) < radix)) { 9041cb0ef41Sopenharmony_ci result *= lradix; 9051cb0ef41Sopenharmony_ci result += (int32_t)b; 9061cb0ef41Sopenharmony_ci } 9071cb0ef41Sopenharmony_ci if (neg) { 9081cb0ef41Sopenharmony_ci result = -result; 9091cb0ef41Sopenharmony_ci } 9101cb0ef41Sopenharmony_ci return result; 9111cb0ef41Sopenharmony_ci} 9121cb0ef41Sopenharmony_ci 9131cb0ef41Sopenharmony_ciint64_t util64_utoi(const char16_t* str, uint32_t radix) 9141cb0ef41Sopenharmony_ci{ 9151cb0ef41Sopenharmony_ci if (radix > 36) { 9161cb0ef41Sopenharmony_ci radix = 36; 9171cb0ef41Sopenharmony_ci } else if (radix < 2) { 9181cb0ef41Sopenharmony_ci radix = 2; 9191cb0ef41Sopenharmony_ci } 9201cb0ef41Sopenharmony_ci int64_t lradix = radix; 9211cb0ef41Sopenharmony_ci 9221cb0ef41Sopenharmony_ci int neg = 0; 9231cb0ef41Sopenharmony_ci if (*str == kUMinus) { 9241cb0ef41Sopenharmony_ci ++str; 9251cb0ef41Sopenharmony_ci neg = 1; 9261cb0ef41Sopenharmony_ci } 9271cb0ef41Sopenharmony_ci int64_t result = 0; 9281cb0ef41Sopenharmony_ci char16_t c; 9291cb0ef41Sopenharmony_ci uint8_t b; 9301cb0ef41Sopenharmony_ci while (((c = *str++) < 0x0080) && (b = digitInfo[c]) && ((b &= 0x7f) < radix)) { 9311cb0ef41Sopenharmony_ci result *= lradix; 9321cb0ef41Sopenharmony_ci result += (int32_t)b; 9331cb0ef41Sopenharmony_ci } 9341cb0ef41Sopenharmony_ci if (neg) { 9351cb0ef41Sopenharmony_ci result = -result; 9361cb0ef41Sopenharmony_ci } 9371cb0ef41Sopenharmony_ci return result; 9381cb0ef41Sopenharmony_ci} 9391cb0ef41Sopenharmony_ci 9401cb0ef41Sopenharmony_ciuint32_t util64_toa(int64_t w, char* buf, uint32_t len, uint32_t radix, UBool raw) 9411cb0ef41Sopenharmony_ci{ 9421cb0ef41Sopenharmony_ci if (radix > 36) { 9431cb0ef41Sopenharmony_ci radix = 36; 9441cb0ef41Sopenharmony_ci } else if (radix < 2) { 9451cb0ef41Sopenharmony_ci radix = 2; 9461cb0ef41Sopenharmony_ci } 9471cb0ef41Sopenharmony_ci int64_t base = radix; 9481cb0ef41Sopenharmony_ci 9491cb0ef41Sopenharmony_ci char* p = buf; 9501cb0ef41Sopenharmony_ci if (len && (w < 0) && (radix == 10) && !raw) { 9511cb0ef41Sopenharmony_ci w = -w; 9521cb0ef41Sopenharmony_ci *p++ = kMinus; 9531cb0ef41Sopenharmony_ci --len; 9541cb0ef41Sopenharmony_ci } else if (len && (w == 0)) { 9551cb0ef41Sopenharmony_ci *p++ = (char)raw ? 0 : asciiDigits[0]; 9561cb0ef41Sopenharmony_ci --len; 9571cb0ef41Sopenharmony_ci } 9581cb0ef41Sopenharmony_ci 9591cb0ef41Sopenharmony_ci while (len && w != 0) { 9601cb0ef41Sopenharmony_ci int64_t n = w / base; 9611cb0ef41Sopenharmony_ci int64_t m = n * base; 9621cb0ef41Sopenharmony_ci int32_t d = (int32_t)(w-m); 9631cb0ef41Sopenharmony_ci *p++ = raw ? (char)d : asciiDigits[d]; 9641cb0ef41Sopenharmony_ci w = n; 9651cb0ef41Sopenharmony_ci --len; 9661cb0ef41Sopenharmony_ci } 9671cb0ef41Sopenharmony_ci if (len) { 9681cb0ef41Sopenharmony_ci *p = 0; // null terminate if room for caller convenience 9691cb0ef41Sopenharmony_ci } 9701cb0ef41Sopenharmony_ci 9711cb0ef41Sopenharmony_ci len = p - buf; 9721cb0ef41Sopenharmony_ci if (*buf == kMinus) { 9731cb0ef41Sopenharmony_ci ++buf; 9741cb0ef41Sopenharmony_ci } 9751cb0ef41Sopenharmony_ci while (--p > buf) { 9761cb0ef41Sopenharmony_ci char c = *p; 9771cb0ef41Sopenharmony_ci *p = *buf; 9781cb0ef41Sopenharmony_ci *buf = c; 9791cb0ef41Sopenharmony_ci ++buf; 9801cb0ef41Sopenharmony_ci } 9811cb0ef41Sopenharmony_ci 9821cb0ef41Sopenharmony_ci return len; 9831cb0ef41Sopenharmony_ci} 9841cb0ef41Sopenharmony_ci#endif 9851cb0ef41Sopenharmony_ci 9861cb0ef41Sopenharmony_ciuint32_t util64_tou(int64_t w, char16_t* buf, uint32_t len, uint32_t radix, UBool raw) 9871cb0ef41Sopenharmony_ci{ 9881cb0ef41Sopenharmony_ci if (radix > 36) { 9891cb0ef41Sopenharmony_ci radix = 36; 9901cb0ef41Sopenharmony_ci } else if (radix < 2) { 9911cb0ef41Sopenharmony_ci radix = 2; 9921cb0ef41Sopenharmony_ci } 9931cb0ef41Sopenharmony_ci int64_t base = radix; 9941cb0ef41Sopenharmony_ci 9951cb0ef41Sopenharmony_ci char16_t* p = buf; 9961cb0ef41Sopenharmony_ci if (len && (w < 0) && (radix == 10) && !raw) { 9971cb0ef41Sopenharmony_ci w = -w; 9981cb0ef41Sopenharmony_ci *p++ = kUMinus; 9991cb0ef41Sopenharmony_ci --len; 10001cb0ef41Sopenharmony_ci } else if (len && (w == 0)) { 10011cb0ef41Sopenharmony_ci *p++ = (char16_t)raw ? 0 : asciiDigits[0]; 10021cb0ef41Sopenharmony_ci --len; 10031cb0ef41Sopenharmony_ci } 10041cb0ef41Sopenharmony_ci 10051cb0ef41Sopenharmony_ci while (len && (w != 0)) { 10061cb0ef41Sopenharmony_ci int64_t n = w / base; 10071cb0ef41Sopenharmony_ci int64_t m = n * base; 10081cb0ef41Sopenharmony_ci int32_t d = (int32_t)(w-m); 10091cb0ef41Sopenharmony_ci *p++ = (char16_t)(raw ? d : asciiDigits[d]); 10101cb0ef41Sopenharmony_ci w = n; 10111cb0ef41Sopenharmony_ci --len; 10121cb0ef41Sopenharmony_ci } 10131cb0ef41Sopenharmony_ci if (len) { 10141cb0ef41Sopenharmony_ci *p = 0; // null terminate if room for caller convenience 10151cb0ef41Sopenharmony_ci } 10161cb0ef41Sopenharmony_ci 10171cb0ef41Sopenharmony_ci len = (uint32_t)(p - buf); 10181cb0ef41Sopenharmony_ci if (*buf == kUMinus) { 10191cb0ef41Sopenharmony_ci ++buf; 10201cb0ef41Sopenharmony_ci } 10211cb0ef41Sopenharmony_ci while (--p > buf) { 10221cb0ef41Sopenharmony_ci char16_t c = *p; 10231cb0ef41Sopenharmony_ci *p = *buf; 10241cb0ef41Sopenharmony_ci *buf = c; 10251cb0ef41Sopenharmony_ci ++buf; 10261cb0ef41Sopenharmony_ci } 10271cb0ef41Sopenharmony_ci 10281cb0ef41Sopenharmony_ci return len; 10291cb0ef41Sopenharmony_ci} 10301cb0ef41Sopenharmony_ci 10311cb0ef41Sopenharmony_ci 10321cb0ef41Sopenharmony_ciU_NAMESPACE_END 10331cb0ef41Sopenharmony_ci 10341cb0ef41Sopenharmony_ci/* U_HAVE_RBNF */ 10351cb0ef41Sopenharmony_ci#endif 1036