| OLD | NEW |
| 1 /* | 1 /* |
| 2 ****************************************************************************** | 2 ****************************************************************************** |
| 3 * Copyright (C) 1997-2014, International Business Machines | 3 * Copyright (C) 1997-2015, International Business Machines |
| 4 * Corporation and others. All Rights Reserved. | 4 * Corporation and others. All Rights Reserved. |
| 5 ****************************************************************************** | 5 ****************************************************************************** |
| 6 * file name: nfrs.cpp | 6 * file name: nfrs.cpp |
| 7 * encoding: US-ASCII | 7 * encoding: US-ASCII |
| 8 * tab size: 8 (not used) | 8 * tab size: 8 (not used) |
| 9 * indentation:4 | 9 * indentation:4 |
| 10 * | 10 * |
| 11 * Modification history | 11 * Modification history |
| 12 * Date Name Comments | 12 * Date Name Comments |
| 13 * 10/11/2001 Doug Ported from ICU4J | 13 * 10/11/2001 Doug Ported from ICU4J |
| 14 */ | 14 */ |
| 15 | 15 |
| 16 #include "nfrs.h" | 16 #include "nfrs.h" |
| 17 | 17 |
| 18 #if U_HAVE_RBNF | 18 #if U_HAVE_RBNF |
| 19 | 19 |
| 20 #include "unicode/uchar.h" | 20 #include "unicode/uchar.h" |
| 21 #include "nfrule.h" | 21 #include "nfrule.h" |
| 22 #include "nfrlist.h" | 22 #include "nfrlist.h" |
| 23 #include "patternprops.h" | 23 #include "patternprops.h" |
| 24 | 24 |
| 25 #ifdef RBNF_DEBUG | 25 #ifdef RBNF_DEBUG |
| 26 #include "cmemory.h" | 26 #include "cmemory.h" |
| 27 #endif | 27 #endif |
| 28 | 28 |
| 29 enum { |
| 30 /** -x */ |
| 31 NEGATIVE_RULE_INDEX = 0, |
| 32 /** x.x */ |
| 33 IMPROPER_FRACTION_RULE_INDEX = 1, |
| 34 /** 0.x */ |
| 35 PROPER_FRACTION_RULE_INDEX = 2, |
| 36 /** x.0 */ |
| 37 MASTER_RULE_INDEX = 3, |
| 38 /** Inf */ |
| 39 INFINITY_RULE_INDEX = 4, |
| 40 /** NaN */ |
| 41 NAN_RULE_INDEX = 5, |
| 42 NON_NUMERICAL_RULE_LENGTH = 6 |
| 43 }; |
| 44 |
| 29 U_NAMESPACE_BEGIN | 45 U_NAMESPACE_BEGIN |
| 30 | 46 |
| 31 #if 0 | 47 #if 0 |
| 32 // euclid's algorithm works with doubles | 48 // euclid's algorithm works with doubles |
| 33 // note, doubles only get us up to one quadrillion or so, which | 49 // 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 | 50 // isn't as much range as we get with longs. We probably still |
| 35 // want either 64-bit math, or BigInteger. | 51 // want either 64-bit math, or BigInteger. |
| 36 | 52 |
| 37 static int64_t | 53 static int64_t |
| 38 util_lcm(int64_t x, int64_t y) | 54 util_lcm(int64_t x, int64_t y) |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 97 // x * y == gcd(x, y) * lcm(x, y) | 113 // x * y == gcd(x, y) * lcm(x, y) |
| 98 return x / gcd * y; | 114 return x / gcd * y; |
| 99 } | 115 } |
| 100 #endif | 116 #endif |
| 101 | 117 |
| 102 static const UChar gPercent = 0x0025; | 118 static const UChar gPercent = 0x0025; |
| 103 static const UChar gColon = 0x003a; | 119 static const UChar gColon = 0x003a; |
| 104 static const UChar gSemicolon = 0x003b; | 120 static const UChar gSemicolon = 0x003b; |
| 105 static const UChar gLineFeed = 0x000a; | 121 static const UChar gLineFeed = 0x000a; |
| 106 | 122 |
| 107 static const UChar gFourSpaces[] = | |
| 108 { | |
| 109 0x20, 0x20, 0x20, 0x20, 0 | |
| 110 }; /* " " */ | |
| 111 static const UChar gPercentPercent[] = | 123 static const UChar gPercentPercent[] = |
| 112 { | 124 { |
| 113 0x25, 0x25, 0 | 125 0x25, 0x25, 0 |
| 114 }; /* "%%" */ | 126 }; /* "%%" */ |
| 115 | 127 |
| 116 static const UChar gNoparse[] = | 128 static const UChar gNoparse[] = |
| 117 { | 129 { |
| 118 0x40, 0x6E, 0x6F, 0x70, 0x61, 0x72, 0x73, 0x65, 0 | 130 0x40, 0x6E, 0x6F, 0x70, 0x61, 0x72, 0x73, 0x65, 0 |
| 119 }; /* "@noparse" */ | 131 }; /* "@noparse" */ |
| 120 | 132 |
| 121 NFRuleSet::NFRuleSet(UnicodeString* descriptions, int32_t index, UErrorCode& sta
tus) | 133 NFRuleSet::NFRuleSet(RuleBasedNumberFormat *_owner, UnicodeString* descriptions,
int32_t index, UErrorCode& status) |
| 122 : name() | 134 : name() |
| 123 , rules(0) | 135 , rules(0) |
| 124 , negativeNumberRule(NULL) | 136 , owner(_owner) |
| 137 , fractionRules() |
| 125 , fIsFractionRuleSet(FALSE) | 138 , fIsFractionRuleSet(FALSE) |
| 126 , fIsPublic(FALSE) | 139 , fIsPublic(FALSE) |
| 127 , fIsParseable(TRUE) | 140 , fIsParseable(TRUE) |
| 128 , fRecursionCount(0) | |
| 129 { | 141 { |
| 130 for (int i = 0; i < 3; ++i) { | 142 for (int32_t i = 0; i < NON_NUMERICAL_RULE_LENGTH; ++i) { |
| 131 fractionRules[i] = NULL; | 143 nonNumericalRules[i] = NULL; |
| 132 } | 144 } |
| 133 | 145 |
| 134 if (U_FAILURE(status)) { | 146 if (U_FAILURE(status)) { |
| 135 return; | 147 return; |
| 136 } | 148 } |
| 137 | 149 |
| 138 UnicodeString& description = descriptions[index]; // !!! make sure index is
valid | 150 UnicodeString& description = descriptions[index]; // !!! make sure index is
valid |
| 139 | 151 |
| 140 if (description.length() == 0) { | 152 if (description.length() == 0) { |
| 141 // throw new IllegalArgumentException("Empty rule set description"); | 153 // throw new IllegalArgumentException("Empty rule set description"); |
| (...skipping 30 matching lines...) Expand all Loading... |
| 172 if ( name.endsWith(gNoparse,8) ) { | 184 if ( name.endsWith(gNoparse,8) ) { |
| 173 fIsParseable = FALSE; | 185 fIsParseable = FALSE; |
| 174 name.truncate(name.length()-8); // remove the @noparse from the name | 186 name.truncate(name.length()-8); // remove the @noparse from the name |
| 175 } | 187 } |
| 176 | 188 |
| 177 // all of the other members of NFRuleSet are initialized | 189 // all of the other members of NFRuleSet are initialized |
| 178 // by parseRules() | 190 // by parseRules() |
| 179 } | 191 } |
| 180 | 192 |
| 181 void | 193 void |
| 182 NFRuleSet::parseRules(UnicodeString& description, const RuleBasedNumberFormat* o
wner, UErrorCode& status) | 194 NFRuleSet::parseRules(UnicodeString& description, UErrorCode& status) |
| 183 { | 195 { |
| 184 // start by creating a Vector whose elements are Strings containing | 196 // start by creating a Vector whose elements are Strings containing |
| 185 // the descriptions of the rules (one rule per element). The rules | 197 // the descriptions of the rules (one rule per element). The rules |
| 186 // are separated by semicolons (there's no escape facility: ALL | 198 // are separated by semicolons (there's no escape facility: ALL |
| 187 // semicolons are rule delimiters) | 199 // semicolons are rule delimiters) |
| 188 | 200 |
| 189 if (U_FAILURE(status)) { | 201 if (U_FAILURE(status)) { |
| 190 return; | 202 return; |
| 191 } | 203 } |
| 192 | 204 |
| (...skipping 17 matching lines...) Expand all Loading... |
| 210 | 222 |
| 211 // for rules that didn't specify a base value, their base values | 223 // for rules that didn't specify a base value, their base values |
| 212 // were initialized to 0. Make another pass through the list and | 224 // were initialized to 0. Make another pass through the list and |
| 213 // set all those rules' base values. We also remove any special | 225 // set all those rules' base values. We also remove any special |
| 214 // rules from the list and put them into their own member variables | 226 // rules from the list and put them into their own member variables |
| 215 int64_t defaultBaseValue = 0; | 227 int64_t defaultBaseValue = 0; |
| 216 | 228 |
| 217 // (this isn't a for loop because we might be deleting items from | 229 // (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 | 230 // the vector-- we want to make sure we only increment i when |
| 219 // we _didn't_ delete aything from the vector) | 231 // we _didn't_ delete aything from the vector) |
| 220 uint32_t i = 0; | 232 int32_t rulesSize = rules.size(); |
| 221 while (i < rules.size()) { | 233 for (int32_t i = 0; i < rulesSize; i++) { |
| 222 NFRule* rule = rules[i]; | 234 NFRule* rule = rules[i]; |
| 235 int64_t baseValue = rule->getBaseValue(); |
| 223 | 236 |
| 224 switch (rule->getType()) { | 237 if (baseValue == 0) { |
| 225 // if the rule's base value is 0, fill in a default | 238 // if the rule's base value is 0, fill in a default |
| 226 // base value (this will be 1 plus the preceding | 239 // base value (this will be 1 plus the preceding |
| 227 // rule's base value for regular rule sets, and the | 240 // rule's base value for regular rule sets, and the |
| 228 // same as the preceding rule's base value in fraction | 241 // same as the preceding rule's base value in fraction |
| 229 // rule sets) | 242 // rule sets) |
| 230 case NFRule::kNoBase: | |
| 231 rule->setBaseValue(defaultBaseValue, status); | 243 rule->setBaseValue(defaultBaseValue, status); |
| 232 if (!isFractionRuleSet()) { | 244 } |
| 233 ++defaultBaseValue; | 245 else { |
| 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: | |
| 241 if (negativeNumberRule) { | |
| 242 delete negativeNumberRule; | |
| 243 } | |
| 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: | |
| 250 if (fractionRules[0]) { | |
| 251 delete fractionRules[0]; | |
| 252 } | |
| 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: | |
| 259 if (fractionRules[1]) { | |
| 260 delete fractionRules[1]; | |
| 261 } | |
| 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: | |
| 268 if (fractionRules[2]) { | |
| 269 delete fractionRules[2]; | |
| 270 } | |
| 271 fractionRules[2] = rules.remove(i); | |
| 272 break; | |
| 273 | |
| 274 // if it's a regular rule that already knows its base value, | 246 // if it's a regular rule that already knows its base value, |
| 275 // check to make sure the rules are in order, and update | 247 // check to make sure the rules are in order, and update |
| 276 // the default base value for the next rule | 248 // the default base value for the next rule |
| 277 default: | 249 if (baseValue < defaultBaseValue) { |
| 278 if (rule->getBaseValue() < defaultBaseValue) { | |
| 279 // throw new IllegalArgumentException("Rules are not in order"); | 250 // throw new IllegalArgumentException("Rules are not in order"); |
| 280 status = U_PARSE_ERROR; | 251 status = U_PARSE_ERROR; |
| 281 return; | 252 return; |
| 282 } | 253 } |
| 283 defaultBaseValue = rule->getBaseValue(); | 254 defaultBaseValue = baseValue; |
| 284 if (!isFractionRuleSet()) { | |
| 285 ++defaultBaseValue; | |
| 286 } | |
| 287 ++i; | |
| 288 break; | |
| 289 } | 255 } |
| 256 if (!fIsFractionRuleSet) { |
| 257 ++defaultBaseValue; |
| 258 } |
| 259 } |
| 260 } |
| 261 |
| 262 /** |
| 263 * Set one of the non-numerical rules. |
| 264 * @param rule The rule to set. |
| 265 */ |
| 266 void NFRuleSet::setNonNumericalRule(NFRule *rule) { |
| 267 int64_t baseValue = rule->getBaseValue(); |
| 268 if (baseValue == NFRule::kNegativeNumberRule) { |
| 269 delete nonNumericalRules[NEGATIVE_RULE_INDEX]; |
| 270 nonNumericalRules[NEGATIVE_RULE_INDEX] = rule; |
| 271 } |
| 272 else if (baseValue == NFRule::kImproperFractionRule) { |
| 273 setBestFractionRule(IMPROPER_FRACTION_RULE_INDEX, rule, TRUE); |
| 274 } |
| 275 else if (baseValue == NFRule::kProperFractionRule) { |
| 276 setBestFractionRule(PROPER_FRACTION_RULE_INDEX, rule, TRUE); |
| 277 } |
| 278 else if (baseValue == NFRule::kMasterRule) { |
| 279 setBestFractionRule(MASTER_RULE_INDEX, rule, TRUE); |
| 280 } |
| 281 else if (baseValue == NFRule::kInfinityRule) { |
| 282 delete nonNumericalRules[INFINITY_RULE_INDEX]; |
| 283 nonNumericalRules[INFINITY_RULE_INDEX] = rule; |
| 284 } |
| 285 else if (baseValue == NFRule::kNaNRule) { |
| 286 delete nonNumericalRules[NAN_RULE_INDEX]; |
| 287 nonNumericalRules[NAN_RULE_INDEX] = rule; |
| 288 } |
| 289 } |
| 290 |
| 291 /** |
| 292 * Determine the best fraction rule to use. Rules matching the decimal point fro
m |
| 293 * DecimalFormatSymbols become the main set of rules to use. |
| 294 * @param originalIndex The index into nonNumericalRules |
| 295 * @param newRule The new rule to consider |
| 296 * @param rememberRule Should the new rule be added to fractionRules. |
| 297 */ |
| 298 void NFRuleSet::setBestFractionRule(int32_t originalIndex, NFRule *newRule, UBoo
l rememberRule) { |
| 299 if (rememberRule) { |
| 300 fractionRules.add(newRule); |
| 301 } |
| 302 NFRule *bestResult = nonNumericalRules[originalIndex]; |
| 303 if (bestResult == NULL) { |
| 304 nonNumericalRules[originalIndex] = newRule; |
| 305 } |
| 306 else { |
| 307 // We have more than one. Which one is better? |
| 308 const DecimalFormatSymbols *decimalFormatSymbols = owner->getDecimalForm
atSymbols(); |
| 309 if (decimalFormatSymbols->getSymbol(DecimalFormatSymbols::kDecimalSepara
torSymbol).charAt(0) |
| 310 == newRule->getDecimalPoint()) |
| 311 { |
| 312 nonNumericalRules[originalIndex] = newRule; |
| 313 } |
| 314 // else leave it alone |
| 290 } | 315 } |
| 291 } | 316 } |
| 292 | 317 |
| 293 NFRuleSet::~NFRuleSet() | 318 NFRuleSet::~NFRuleSet() |
| 294 { | 319 { |
| 295 delete negativeNumberRule; | 320 for (int i = 0; i < NON_NUMERICAL_RULE_LENGTH; i++) { |
| 296 delete fractionRules[0]; | 321 if (i != IMPROPER_FRACTION_RULE_INDEX |
| 297 delete fractionRules[1]; | 322 && i != PROPER_FRACTION_RULE_INDEX |
| 298 delete fractionRules[2]; | 323 && i != MASTER_RULE_INDEX) |
| 324 { |
| 325 delete nonNumericalRules[i]; |
| 326 } |
| 327 // else it will be deleted via NFRuleList fractionRules |
| 328 } |
| 299 } | 329 } |
| 300 | 330 |
| 301 static UBool | 331 static UBool |
| 302 util_equalRules(const NFRule* rule1, const NFRule* rule2) | 332 util_equalRules(const NFRule* rule1, const NFRule* rule2) |
| 303 { | 333 { |
| 304 if (rule1) { | 334 if (rule1) { |
| 305 if (rule2) { | 335 if (rule2) { |
| 306 return *rule1 == *rule2; | 336 return *rule1 == *rule2; |
| 307 } | 337 } |
| 308 } else if (!rule2) { | 338 } else if (!rule2) { |
| 309 return TRUE; | 339 return TRUE; |
| 310 } | 340 } |
| 311 return FALSE; | 341 return FALSE; |
| 312 } | 342 } |
| 313 | 343 |
| 314 UBool | 344 UBool |
| 315 NFRuleSet::operator==(const NFRuleSet& rhs) const | 345 NFRuleSet::operator==(const NFRuleSet& rhs) const |
| 316 { | 346 { |
| 317 if (rules.size() == rhs.rules.size() && | 347 if (rules.size() == rhs.rules.size() && |
| 318 fIsFractionRuleSet == rhs.fIsFractionRuleSet && | 348 fIsFractionRuleSet == rhs.fIsFractionRuleSet && |
| 319 name == rhs.name && | 349 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 | 350 |
| 351 // ...then compare the non-numerical rule lists... |
| 352 for (int i = 0; i < NON_NUMERICAL_RULE_LENGTH; i++) { |
| 353 if (!util_equalRules(nonNumericalRules[i], rhs.nonNumericalRules[i])
) { |
| 354 return FALSE; |
| 355 } |
| 356 } |
| 357 |
| 358 // ...then compare the rule lists... |
| 325 for (uint32_t i = 0; i < rules.size(); ++i) { | 359 for (uint32_t i = 0; i < rules.size(); ++i) { |
| 326 if (*rules[i] != *rhs.rules[i]) { | 360 if (*rules[i] != *rhs.rules[i]) { |
| 327 return FALSE; | 361 return FALSE; |
| 328 } | 362 } |
| 329 } | 363 } |
| 330 return TRUE; | 364 return TRUE; |
| 331 } | 365 } |
| 332 return FALSE; | 366 return FALSE; |
| 333 } | 367 } |
| 334 | 368 |
| 335 #define RECURSION_LIMIT 50 | 369 void |
| 370 NFRuleSet::setDecimalFormatSymbols(const DecimalFormatSymbols &newSymbols, UErro
rCode& status) { |
| 371 for (uint32_t i = 0; i < rules.size(); ++i) { |
| 372 rules[i]->setDecimalFormatSymbols(newSymbols, status); |
| 373 } |
| 374 // Switch the fraction rules to mirror the DecimalFormatSymbols. |
| 375 for (int32_t nonNumericalIdx = IMPROPER_FRACTION_RULE_INDEX; nonNumericalIdx
<= MASTER_RULE_INDEX; nonNumericalIdx++) { |
| 376 if (nonNumericalRules[nonNumericalIdx]) { |
| 377 for (uint32_t fIdx = 0; fIdx < fractionRules.size(); fIdx++) { |
| 378 NFRule *fractionRule = fractionRules[fIdx]; |
| 379 if (nonNumericalRules[nonNumericalIdx]->getBaseValue() == fracti
onRule->getBaseValue()) { |
| 380 setBestFractionRule(nonNumericalIdx, fractionRule, FALSE); |
| 381 } |
| 382 } |
| 383 } |
| 384 } |
| 336 | 385 |
| 337 void | 386 for (uint32_t nnrIdx = 0; nnrIdx < NON_NUMERICAL_RULE_LENGTH; nnrIdx++) { |
| 338 NFRuleSet::format(int64_t number, UnicodeString& toAppendTo, int32_t pos, UError
Code& status) const | 387 NFRule *rule = nonNumericalRules[nnrIdx]; |
| 339 { | 388 if (rule) { |
| 340 NFRule *rule = findNormalRule(number); | 389 rule->setDecimalFormatSymbols(newSymbols, status); |
| 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 { | |
| 347 rule->doFormat(number, toAppendTo, pos, status); | |
| 348 ncThis->fRecursionCount--; | |
| 349 } | 390 } |
| 350 } | 391 } |
| 351 } | 392 } |
| 352 | 393 |
| 394 #define RECURSION_LIMIT 64 |
| 395 |
| 353 void | 396 void |
| 354 NFRuleSet::format(double number, UnicodeString& toAppendTo, int32_t pos, UErrorC
ode& status) const | 397 NFRuleSet::format(int64_t number, UnicodeString& toAppendTo, int32_t pos, int32_
t recursionCount, UErrorCode& status) const |
| 355 { | 398 { |
| 356 NFRule *rule = findDoubleRule(number); | 399 if (recursionCount >= RECURSION_LIMIT) { |
| 400 // stop recursion |
| 401 status = U_INVALID_STATE_ERROR; |
| 402 return; |
| 403 } |
| 404 const NFRule *rule = findNormalRule(number); |
| 357 if (rule) { // else error, but can't report it | 405 if (rule) { // else error, but can't report it |
| 358 NFRuleSet* ncThis = (NFRuleSet*)this; | 406 rule->doFormat(number, toAppendTo, pos, ++recursionCount, status); |
| 359 if (ncThis->fRecursionCount++ >= RECURSION_LIMIT) { | |
| 360 // stop recursion | |
| 361 ncThis->fRecursionCount = 0; | |
| 362 } else { | |
| 363 rule->doFormat(number, toAppendTo, pos, status); | |
| 364 ncThis->fRecursionCount--; | |
| 365 } | |
| 366 } | 407 } |
| 367 } | 408 } |
| 368 | 409 |
| 369 NFRule* | 410 void |
| 411 NFRuleSet::format(double number, UnicodeString& toAppendTo, int32_t pos, int32_t
recursionCount, UErrorCode& status) const |
| 412 { |
| 413 if (recursionCount >= RECURSION_LIMIT) { |
| 414 // stop recursion |
| 415 status = U_INVALID_STATE_ERROR; |
| 416 return; |
| 417 } |
| 418 const NFRule *rule = findDoubleRule(number); |
| 419 if (rule) { // else error, but can't report it |
| 420 rule->doFormat(number, toAppendTo, pos, ++recursionCount, status); |
| 421 } |
| 422 } |
| 423 |
| 424 const NFRule* |
| 370 NFRuleSet::findDoubleRule(double number) const | 425 NFRuleSet::findDoubleRule(double number) const |
| 371 { | 426 { |
| 372 // if this is a fraction rule set, use findFractionRuleSetRule() | 427 // if this is a fraction rule set, use findFractionRuleSetRule() |
| 373 if (isFractionRuleSet()) { | 428 if (isFractionRuleSet()) { |
| 374 return findFractionRuleSetRule(number); | 429 return findFractionRuleSetRule(number); |
| 375 } | 430 } |
| 376 | 431 |
| 432 if (uprv_isNaN(number)) { |
| 433 const NFRule *rule = nonNumericalRules[NAN_RULE_INDEX]; |
| 434 if (!rule) { |
| 435 rule = owner->getDefaultNaNRule(); |
| 436 } |
| 437 return rule; |
| 438 } |
| 439 |
| 377 // if the number is negative, return the negative number rule | 440 // if the number is negative, return the negative number rule |
| 378 // (if there isn't a negative-number rule, we pretend it's a | 441 // (if there isn't a negative-number rule, we pretend it's a |
| 379 // positive number) | 442 // positive number) |
| 380 if (number < 0) { | 443 if (number < 0) { |
| 381 if (negativeNumberRule) { | 444 if (nonNumericalRules[NEGATIVE_RULE_INDEX]) { |
| 382 return negativeNumberRule; | 445 return nonNumericalRules[NEGATIVE_RULE_INDEX]; |
| 383 } else { | 446 } else { |
| 384 number = -number; | 447 number = -number; |
| 385 } | 448 } |
| 386 } | 449 } |
| 387 | 450 |
| 451 if (uprv_isInfinite(number)) { |
| 452 const NFRule *rule = nonNumericalRules[INFINITY_RULE_INDEX]; |
| 453 if (!rule) { |
| 454 rule = owner->getDefaultInfinityRule(); |
| 455 } |
| 456 return rule; |
| 457 } |
| 458 |
| 388 // if the number isn't an integer, we use one of the fraction rules... | 459 // if the number isn't an integer, we use one of the fraction rules... |
| 389 if (number != uprv_floor(number)) { | 460 if (number != uprv_floor(number)) { |
| 390 // if the number is between 0 and 1, return the proper | 461 // if the number is between 0 and 1, return the proper |
| 391 // fraction rule | 462 // fraction rule |
| 392 if (number < 1 && fractionRules[1]) { | 463 if (number < 1 && nonNumericalRules[PROPER_FRACTION_RULE_INDEX]) { |
| 393 return fractionRules[1]; | 464 return nonNumericalRules[PROPER_FRACTION_RULE_INDEX]; |
| 394 } | 465 } |
| 395 // otherwise, return the improper fraction rule | 466 // otherwise, return the improper fraction rule |
| 396 else if (fractionRules[0]) { | 467 else if (nonNumericalRules[IMPROPER_FRACTION_RULE_INDEX]) { |
| 397 return fractionRules[0]; | 468 return nonNumericalRules[IMPROPER_FRACTION_RULE_INDEX]; |
| 398 } | 469 } |
| 399 } | 470 } |
| 400 | 471 |
| 401 // if there's a master rule, use it to format the number | 472 // if there's a master rule, use it to format the number |
| 402 if (fractionRules[2]) { | 473 if (nonNumericalRules[MASTER_RULE_INDEX]) { |
| 403 return fractionRules[2]; | 474 return nonNumericalRules[MASTER_RULE_INDEX]; |
| 404 } | 475 } |
| 405 | 476 |
| 406 // and if we haven't yet returned a rule, use findNormalRule() | 477 // and if we haven't yet returned a rule, use findNormalRule() |
| 407 // to find the applicable rule | 478 // to find the applicable rule |
| 408 int64_t r = util64_fromDouble(number + 0.5); | 479 int64_t r = util64_fromDouble(number + 0.5); |
| 409 return findNormalRule(r); | 480 return findNormalRule(r); |
| 410 } | 481 } |
| 411 | 482 |
| 412 NFRule * | 483 const NFRule * |
| 413 NFRuleSet::findNormalRule(int64_t number) const | 484 NFRuleSet::findNormalRule(int64_t number) const |
| 414 { | 485 { |
| 415 // if this is a fraction rule set, use findFractionRuleSetRule() | 486 // if this is a fraction rule set, use findFractionRuleSetRule() |
| 416 // to find the rule (we should only go into this clause if the | 487 // to find the rule (we should only go into this clause if the |
| 417 // value is 0) | 488 // value is 0) |
| 418 if (fIsFractionRuleSet) { | 489 if (fIsFractionRuleSet) { |
| 419 return findFractionRuleSetRule((double)number); | 490 return findFractionRuleSetRule((double)number); |
| 420 } | 491 } |
| 421 | 492 |
| 422 // if the number is negative, return the negative-number rule | 493 // if the number is negative, return the negative-number rule |
| 423 // (if there isn't one, pretend the number is positive) | 494 // (if there isn't one, pretend the number is positive) |
| 424 if (number < 0) { | 495 if (number < 0) { |
| 425 if (negativeNumberRule) { | 496 if (nonNumericalRules[NEGATIVE_RULE_INDEX]) { |
| 426 return negativeNumberRule; | 497 return nonNumericalRules[NEGATIVE_RULE_INDEX]; |
| 427 } else { | 498 } else { |
| 428 number = -number; | 499 number = -number; |
| 429 } | 500 } |
| 430 } | 501 } |
| 431 | 502 |
| 432 // we have to repeat the preceding two checks, even though we | 503 // we have to repeat the preceding two checks, even though we |
| 433 // do them in findRule(), because the version of format() that | 504 // do them in findRule(), because the version of format() that |
| 434 // takes a long bypasses findRule() and goes straight to this | 505 // takes a long bypasses findRule() and goes straight to this |
| 435 // function. This function does skip the fraction rules since | 506 // function. This function does skip the fraction rules since |
| 436 // we know the value is an integer (it also skips the master | 507 // we know the value is an integer (it also skips the master |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 473 // return | 544 // return |
| 474 if (result->shouldRollBack((double)number)) { | 545 if (result->shouldRollBack((double)number)) { |
| 475 if (hi == 1) { // bad rule set, no prior rule to rollback to from th
is base | 546 if (hi == 1) { // bad rule set, no prior rule to rollback to from th
is base |
| 476 return NULL; | 547 return NULL; |
| 477 } | 548 } |
| 478 result = rules[hi - 2]; | 549 result = rules[hi - 2]; |
| 479 } | 550 } |
| 480 return result; | 551 return result; |
| 481 } | 552 } |
| 482 // else use the master rule | 553 // else use the master rule |
| 483 return fractionRules[2]; | 554 return nonNumericalRules[MASTER_RULE_INDEX]; |
| 484 } | 555 } |
| 485 | 556 |
| 486 /** | 557 /** |
| 487 * If this rule is a fraction rule set, this function is used by | 558 * If this rule is a fraction rule set, this function is used by |
| 488 * findRule() to select the most appropriate rule for formatting | 559 * findRule() to select the most appropriate rule for formatting |
| 489 * the number. Basically, the base value of each rule in the rule | 560 * the number. Basically, the base value of each rule in the rule |
| 490 * set is treated as the denominator of a fraction. Whichever | 561 * set is treated as the denominator of a fraction. Whichever |
| 491 * denominator can produce the fraction closest in value to the | 562 * denominator can produce the fraction closest in value to the |
| 492 * number passed in is the result. If there's a tie, the earlier | 563 * number passed in is the result. If there's a tie, the earlier |
| 493 * one in the list wins. (If there are two rules in a row with the | 564 * one in the list wins. (If there are two rules in a row with the |
| 494 * same base value, the first one is used when the numerator of the | 565 * same base value, the first one is used when the numerator of the |
| 495 * fraction would be 1, and the second rule is used the rest of the | 566 * fraction would be 1, and the second rule is used the rest of the |
| 496 * time. | 567 * time. |
| 497 * @param number The number being formatted (which will always be | 568 * @param number The number being formatted (which will always be |
| 498 * a number between 0 and 1) | 569 * a number between 0 and 1) |
| 499 * @return The rule to use to format this number | 570 * @return The rule to use to format this number |
| 500 */ | 571 */ |
| 501 NFRule* | 572 const NFRule* |
| 502 NFRuleSet::findFractionRuleSetRule(double number) const | 573 NFRuleSet::findFractionRuleSetRule(double number) const |
| 503 { | 574 { |
| 504 // the obvious way to do this (multiply the value being formatted | 575 // the obvious way to do this (multiply the value being formatted |
| 505 // by each rule's base value until you get an integral result) | 576 // by each rule's base value until you get an integral result) |
| 506 // doesn't work because of rounding error. This method is more | 577 // doesn't work because of rounding error. This method is more |
| 507 // accurate | 578 // accurate |
| 508 | 579 |
| 509 // find the least common multiple of the rules' base values | 580 // find the least common multiple of the rules' base values |
| 510 // and multiply this by the number being formatted. This is | 581 // and multiply this by the number being formatted. This is |
| 511 // all the precision we need, and we can do all of the rest | 582 // all the precision we need, and we can do all of the rest |
| (...skipping 112 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 624 ParsePosition workingPos = pos; | 695 ParsePosition workingPos = pos; |
| 625 | 696 |
| 626 #ifdef RBNF_DEBUG | 697 #ifdef RBNF_DEBUG |
| 627 fprintf(stderr, "<nfrs> %x '", this); | 698 fprintf(stderr, "<nfrs> %x '", this); |
| 628 dumpUS(stderr, name); | 699 dumpUS(stderr, name); |
| 629 fprintf(stderr, "' text '"); | 700 fprintf(stderr, "' text '"); |
| 630 dumpUS(stderr, text); | 701 dumpUS(stderr, text); |
| 631 fprintf(stderr, "'\n"); | 702 fprintf(stderr, "'\n"); |
| 632 fprintf(stderr, " parse negative: %d\n", this, negativeNumberRule != 0); | 703 fprintf(stderr, " parse negative: %d\n", this, negativeNumberRule != 0); |
| 633 #endif | 704 #endif |
| 634 | 705 // Try each of the negative rules, fraction rules, infinity rules and NaN ru
les |
| 635 // start by trying the negative number rule (if there is one) | 706 for (int i = 0; i < NON_NUMERICAL_RULE_LENGTH; i++) { |
| 636 if (negativeNumberRule) { | 707 if (nonNumericalRules[i]) { |
| 637 Formattable tempResult; | 708 Formattable tempResult; |
| 638 #ifdef RBNF_DEBUG | 709 UBool success = nonNumericalRules[i]->doParse(text, workingPos, 0, u
pperBound, tempResult); |
| 639 fprintf(stderr, " <nfrs before negative> %x ub: %g\n", negativeNumberRu
le, upperBound); | 710 if (success && (workingPos.getIndex() > highWaterMark.getIndex())) { |
| 640 #endif | 711 result = tempResult; |
| 641 UBool success = negativeNumberRule->doParse(text, workingPos, 0, upperBo
und, tempResult); | 712 highWaterMark = workingPos; |
| 642 #ifdef RBNF_DEBUG | |
| 643 fprintf(stderr, " <nfrs after negative> success: %d wpi: %d\n", success
, workingPos.getIndex()); | |
| 644 #endif | |
| 645 if (success && workingPos.getIndex() > highWaterMark.getIndex()) { | |
| 646 result = tempResult; | |
| 647 highWaterMark = workingPos; | |
| 648 } | |
| 649 workingPos = pos; | |
| 650 } | |
| 651 #ifdef RBNF_DEBUG | |
| 652 fprintf(stderr, "<nfrs> continue fractional with text '"); | |
| 653 dumpUS(stderr, text); | |
| 654 fprintf(stderr, "' hwm: %d\n", highWaterMark.getIndex()); | |
| 655 #endif | |
| 656 // then try each of the fraction rules | |
| 657 { | |
| 658 for (int i = 0; i < 3; i++) { | |
| 659 if (fractionRules[i]) { | |
| 660 Formattable tempResult; | |
| 661 UBool success = fractionRules[i]->doParse(text, workingPos, 0, u
pperBound, tempResult); | |
| 662 if (success && (workingPos.getIndex() > highWaterMark.getIndex()
)) { | |
| 663 result = tempResult; | |
| 664 highWaterMark = workingPos; | |
| 665 } | |
| 666 workingPos = pos; | |
| 667 } | 713 } |
| 714 workingPos = pos; |
| 668 } | 715 } |
| 669 } | 716 } |
| 670 #ifdef RBNF_DEBUG | 717 #ifdef RBNF_DEBUG |
| 671 fprintf(stderr, "<nfrs> continue other with text '"); | 718 fprintf(stderr, "<nfrs> continue other with text '"); |
| 672 dumpUS(stderr, text); | 719 dumpUS(stderr, text); |
| 673 fprintf(stderr, "' hwm: %d\n", highWaterMark.getIndex()); | 720 fprintf(stderr, "' hwm: %d\n", highWaterMark.getIndex()); |
| 674 #endif | 721 #endif |
| 675 | 722 |
| 676 // finally, go through the regular rules one at a time. We start | 723 // finally, go through the regular rules one at a time. We start |
| 677 // at the end of the list because we want to try matching the most | 724 // at the end of the list because we want to try matching the most |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 713 // first character we didn't use, and return the result that | 760 // first character we didn't use, and return the result that |
| 714 // corresponds to that string of characters | 761 // corresponds to that string of characters |
| 715 pos = highWaterMark; | 762 pos = highWaterMark; |
| 716 | 763 |
| 717 return 1; | 764 return 1; |
| 718 } | 765 } |
| 719 | 766 |
| 720 void | 767 void |
| 721 NFRuleSet::appendRules(UnicodeString& result) const | 768 NFRuleSet::appendRules(UnicodeString& result) const |
| 722 { | 769 { |
| 770 uint32_t i; |
| 771 |
| 723 // the rule set name goes first... | 772 // the rule set name goes first... |
| 724 result.append(name); | 773 result.append(name); |
| 725 result.append(gColon); | 774 result.append(gColon); |
| 726 result.append(gLineFeed); | 775 result.append(gLineFeed); |
| 727 | 776 |
| 728 // followed by the regular rules... | 777 // followed by the regular rules... |
| 729 for (uint32_t i = 0; i < rules.size(); i++) { | 778 for (i = 0; i < rules.size(); i++) { |
| 730 result.append(gFourSpaces, 4); | |
| 731 rules[i]->_appendRuleText(result); | 779 rules[i]->_appendRuleText(result); |
| 732 result.append(gLineFeed); | 780 result.append(gLineFeed); |
| 733 } | 781 } |
| 734 | 782 |
| 735 // followed by the special rules (if they exist) | 783 // followed by the special rules (if they exist) |
| 736 if (negativeNumberRule) { | 784 for (i = 0; i < NON_NUMERICAL_RULE_LENGTH; ++i) { |
| 737 result.append(gFourSpaces, 4); | 785 NFRule *rule = nonNumericalRules[i]; |
| 738 negativeNumberRule->_appendRuleText(result); | 786 if (nonNumericalRules[i]) { |
| 739 result.append(gLineFeed); | 787 if (rule->getBaseValue() == NFRule::kImproperFractionRule |
| 740 } | 788 || rule->getBaseValue() == NFRule::kProperFractionRule |
| 741 | 789 || rule->getBaseValue() == NFRule::kMasterRule) |
| 742 { | 790 { |
| 743 for (uint32_t i = 0; i < 3; ++i) { | 791 for (uint32_t fIdx = 0; fIdx < fractionRules.size(); fIdx++) { |
| 744 if (fractionRules[i]) { | 792 NFRule *fractionRule = fractionRules[fIdx]; |
| 745 result.append(gFourSpaces, 4); | 793 if (fractionRule->getBaseValue() == rule->getBaseValue()) { |
| 746 fractionRules[i]->_appendRuleText(result); | 794 fractionRule->_appendRuleText(result); |
| 795 result.append(gLineFeed); |
| 796 } |
| 797 } |
| 798 } |
| 799 else { |
| 800 rule->_appendRuleText(result); |
| 747 result.append(gLineFeed); | 801 result.append(gLineFeed); |
| 748 } | 802 } |
| 749 } | 803 } |
| 750 } | 804 } |
| 751 } | 805 } |
| 752 | 806 |
| 753 // utility functions | 807 // utility functions |
| 754 | 808 |
| 755 int64_t util64_fromDouble(double d) { | 809 int64_t util64_fromDouble(double d) { |
| 756 int64_t result = 0; | 810 int64_t result = 0; |
| (...skipping 205 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 962 | 1016 |
| 963 return len; | 1017 return len; |
| 964 } | 1018 } |
| 965 | 1019 |
| 966 | 1020 |
| 967 U_NAMESPACE_END | 1021 U_NAMESPACE_END |
| 968 | 1022 |
| 969 /* U_HAVE_RBNF */ | 1023 /* U_HAVE_RBNF */ |
| 970 #endif | 1024 #endif |
| 971 | 1025 |
| OLD | NEW |