1 // 2017 and later: Unicode, Inc. and others. 2 // License & terms of use: http://www.unicode.org/copyright.html 3 4 #include "unicode/utypes.h" 5 6 #if !UCONFIG_NO_FORMATTING 7 8 #include "uassert.h" 9 #include "unicode/numberformatter.h" 10 #include "number_decimalquantity.h" 11 #include "number_formatimpl.h" 12 #include "umutex.h" 13 #include "number_asformat.h" 14 #include "number_skeletons.h" 15 #include "number_utils.h" 16 #include "number_utypes.h" 17 #include "util.h" 18 #include "fphdlimp.h" 19 20 using namespace icu; 21 using namespace icu::number; 22 using namespace icu::number::impl; 23 24 template<typename Derived> 25 Derived NumberFormatterSettings<Derived>::notation(const Notation& notation) const& { 26 Derived copy(*this); 27 // NOTE: Slicing is OK. 28 copy.fMacros.notation = notation; 29 return copy; 30 } 31 32 template<typename Derived> 33 Derived NumberFormatterSettings<Derived>::notation(const Notation& notation)&& { 34 Derived move(std::move(*this)); 35 // NOTE: Slicing is OK. 36 move.fMacros.notation = notation; 37 return move; 38 } 39 40 template<typename Derived> 41 Derived NumberFormatterSettings<Derived>::unit(const icu::MeasureUnit& unit) const& { 42 Derived copy(*this); 43 // NOTE: Slicing occurs here. However, CurrencyUnit can be restored from MeasureUnit. 44 // TimeUnit may be affected, but TimeUnit is not as relevant to number formatting. 45 copy.fMacros.unit = unit; 46 return copy; 47 } 48 49 template<typename Derived> 50 Derived NumberFormatterSettings<Derived>::unit(const icu::MeasureUnit& unit)&& { 51 Derived move(std::move(*this)); 52 // See comments above about slicing. 53 move.fMacros.unit = unit; 54 return move; 55 } 56 57 template<typename Derived> 58 Derived NumberFormatterSettings<Derived>::adoptUnit(icu::MeasureUnit* unit) const& { 59 Derived copy(*this); 60 // Just move the unit into the MacroProps by value, and delete it since we have ownership. 61 // NOTE: Slicing occurs here. However, CurrencyUnit can be restored from MeasureUnit. 62 // TimeUnit may be affected, but TimeUnit is not as relevant to number formatting. 63 if (unit != nullptr) { 64 // TODO: On nullptr, reset to default value? 65 copy.fMacros.unit = std::move(*unit); 66 delete unit; 67 } 68 return copy; 69 } 70 71 template<typename Derived> 72 Derived NumberFormatterSettings<Derived>::adoptUnit(icu::MeasureUnit* unit)&& { 73 Derived move(std::move(*this)); 74 // See comments above about slicing and ownership. 75 if (unit != nullptr) { 76 // TODO: On nullptr, reset to default value? 77 move.fMacros.unit = std::move(*unit); 78 delete unit; 79 } 80 return move; 81 } 82 83 template<typename Derived> 84 Derived NumberFormatterSettings<Derived>::perUnit(const icu::MeasureUnit& perUnit) const& { 85 Derived copy(*this); 86 // See comments above about slicing. 87 copy.fMacros.perUnit = perUnit; 88 return copy; 89 } 90 91 template<typename Derived> 92 Derived NumberFormatterSettings<Derived>::perUnit(const icu::MeasureUnit& perUnit)&& { 93 Derived move(std::move(*this)); 94 // See comments above about slicing. 95 move.fMacros.perUnit = perUnit; 96 return move; 97 } 98 99 template<typename Derived> 100 Derived NumberFormatterSettings<Derived>::adoptPerUnit(icu::MeasureUnit* perUnit) const& { 101 Derived copy(*this); 102 // See comments above about slicing and ownership. 103 if (perUnit != nullptr) { 104 // TODO: On nullptr, reset to default value? 105 copy.fMacros.perUnit = std::move(*perUnit); 106 delete perUnit; 107 } 108 return copy; 109 } 110 111 template<typename Derived> 112 Derived NumberFormatterSettings<Derived>::adoptPerUnit(icu::MeasureUnit* perUnit)&& { 113 Derived move(std::move(*this)); 114 // See comments above about slicing and ownership. 115 if (perUnit != nullptr) { 116 // TODO: On nullptr, reset to default value? 117 move.fMacros.perUnit = std::move(*perUnit); 118 delete perUnit; 119 } 120 return move; 121 } 122 123 template<typename Derived> 124 Derived NumberFormatterSettings<Derived>::precision(const Precision& precision) const& { 125 Derived copy(*this); 126 // NOTE: Slicing is OK. 127 copy.fMacros.precision = precision; 128 return copy; 129 } 130 131 template<typename Derived> 132 Derived NumberFormatterSettings<Derived>::precision(const Precision& precision)&& { 133 Derived move(std::move(*this)); 134 // NOTE: Slicing is OK. 135 move.fMacros.precision = precision; 136 return move; 137 } 138 139 template<typename Derived> 140 Derived NumberFormatterSettings<Derived>::roundingMode(UNumberFormatRoundingMode roundingMode) const& { 141 Derived copy(*this); 142 copy.fMacros.roundingMode = roundingMode; 143 return copy; 144 } 145 146 template<typename Derived> 147 Derived NumberFormatterSettings<Derived>::roundingMode(UNumberFormatRoundingMode roundingMode)&& { 148 Derived move(std::move(*this)); 149 move.fMacros.roundingMode = roundingMode; 150 return move; 151 } 152 153 template<typename Derived> 154 Derived NumberFormatterSettings<Derived>::grouping(UGroupingStrategy strategy) const& { 155 Derived copy(*this); 156 // NOTE: This is slightly different than how the setting is stored in Java 157 // because we want to put it on the stack. 158 copy.fMacros.grouper = Grouper::forStrategy(strategy); 159 return copy; 160 } 161 162 template<typename Derived> 163 Derived NumberFormatterSettings<Derived>::grouping(UGroupingStrategy strategy)&& { 164 Derived move(std::move(*this)); 165 move.fMacros.grouper = Grouper::forStrategy(strategy); 166 return move; 167 } 168 169 template<typename Derived> 170 Derived NumberFormatterSettings<Derived>::integerWidth(const IntegerWidth& style) const& { 171 Derived copy(*this); 172 copy.fMacros.integerWidth = style; 173 return copy; 174 } 175 176 template<typename Derived> 177 Derived NumberFormatterSettings<Derived>::integerWidth(const IntegerWidth& style)&& { 178 Derived move(std::move(*this)); 179 move.fMacros.integerWidth = style; 180 return move; 181 } 182 183 template<typename Derived> 184 Derived NumberFormatterSettings<Derived>::symbols(const DecimalFormatSymbols& symbols) const& { 185 Derived copy(*this); 186 copy.fMacros.symbols.setTo(symbols); 187 return copy; 188 } 189 190 template<typename Derived> 191 Derived NumberFormatterSettings<Derived>::symbols(const DecimalFormatSymbols& symbols)&& { 192 Derived move(std::move(*this)); 193 move.fMacros.symbols.setTo(symbols); 194 return move; 195 } 196 197 template<typename Derived> 198 Derived NumberFormatterSettings<Derived>::adoptSymbols(NumberingSystem* ns) const& { 199 Derived copy(*this); 200 copy.fMacros.symbols.setTo(ns); 201 return copy; 202 } 203 204 template<typename Derived> 205 Derived NumberFormatterSettings<Derived>::adoptSymbols(NumberingSystem* ns)&& { 206 Derived move(std::move(*this)); 207 move.fMacros.symbols.setTo(ns); 208 return move; 209 } 210 211 template<typename Derived> 212 Derived NumberFormatterSettings<Derived>::unitWidth(UNumberUnitWidth width) const& { 213 Derived copy(*this); 214 copy.fMacros.unitWidth = width; 215 return copy; 216 } 217 218 template<typename Derived> 219 Derived NumberFormatterSettings<Derived>::unitWidth(UNumberUnitWidth width)&& { 220 Derived move(std::move(*this)); 221 move.fMacros.unitWidth = width; 222 return move; 223 } 224 225 template<typename Derived> 226 Derived NumberFormatterSettings<Derived>::sign(UNumberSignDisplay style) const& { 227 Derived copy(*this); 228 copy.fMacros.sign = style; 229 return copy; 230 } 231 232 template<typename Derived> 233 Derived NumberFormatterSettings<Derived>::sign(UNumberSignDisplay style)&& { 234 Derived move(std::move(*this)); 235 move.fMacros.sign = style; 236 return move; 237 } 238 239 template<typename Derived> 240 Derived NumberFormatterSettings<Derived>::decimal(UNumberDecimalSeparatorDisplay style) const& { 241 Derived copy(*this); 242 copy.fMacros.decimal = style; 243 return copy; 244 } 245 246 template<typename Derived> 247 Derived NumberFormatterSettings<Derived>::decimal(UNumberDecimalSeparatorDisplay style)&& { 248 Derived move(std::move(*this)); 249 move.fMacros.decimal = style; 250 return move; 251 } 252 253 template<typename Derived> 254 Derived NumberFormatterSettings<Derived>::scale(const Scale& scale) const& { 255 Derived copy(*this); 256 copy.fMacros.scale = scale; 257 return copy; 258 } 259 260 template<typename Derived> 261 Derived NumberFormatterSettings<Derived>::scale(const Scale& scale)&& { 262 Derived move(std::move(*this)); 263 move.fMacros.scale = scale; 264 return move; 265 } 266 267 template<typename Derived> 268 Derived NumberFormatterSettings<Derived>::padding(const Padder& padder) const& { 269 Derived copy(*this); 270 copy.fMacros.padder = padder; 271 return copy; 272 } 273 274 template<typename Derived> 275 Derived NumberFormatterSettings<Derived>::padding(const Padder& padder)&& { 276 Derived move(std::move(*this)); 277 move.fMacros.padder = padder; 278 return move; 279 } 280 281 template<typename Derived> 282 Derived NumberFormatterSettings<Derived>::threshold(int32_t threshold) const& { 283 Derived copy(*this); 284 copy.fMacros.threshold = threshold; 285 return copy; 286 } 287 288 template<typename Derived> 289 Derived NumberFormatterSettings<Derived>::threshold(int32_t threshold)&& { 290 Derived move(std::move(*this)); 291 move.fMacros.threshold = threshold; 292 return move; 293 } 294 295 template<typename Derived> 296 Derived NumberFormatterSettings<Derived>::macros(const impl::MacroProps& macros) const& { 297 Derived copy(*this); 298 copy.fMacros = macros; 299 return copy; 300 } 301 302 template<typename Derived> 303 Derived NumberFormatterSettings<Derived>::macros(const impl::MacroProps& macros)&& { 304 Derived move(std::move(*this)); 305 move.fMacros = macros; 306 return move; 307 } 308 309 template<typename Derived> 310 Derived NumberFormatterSettings<Derived>::macros(impl::MacroProps&& macros) const& { 311 Derived copy(*this); 312 copy.fMacros = std::move(macros); 313 return copy; 314 } 315 316 template<typename Derived> 317 Derived NumberFormatterSettings<Derived>::macros(impl::MacroProps&& macros)&& { 318 Derived move(std::move(*this)); 319 move.fMacros = std::move(macros); 320 return move; 321 } 322 323 template<typename Derived> 324 UnicodeString NumberFormatterSettings<Derived>::toSkeleton(UErrorCode& status) const { 325 if (fMacros.copyErrorTo(status)) { 326 return ICU_Utility::makeBogusString(); 327 } 328 return skeleton::generate(fMacros, status); 329 } 330 331 // Declare all classes that implement NumberFormatterSettings 332 // See https://stackoverflow.com/a/495056/1407170 333 template 334 class icu::number::NumberFormatterSettings<icu::number::UnlocalizedNumberFormatter>; 335 template 336 class icu::number::NumberFormatterSettings<icu::number::LocalizedNumberFormatter>; 337 338 339 UnlocalizedNumberFormatter NumberFormatter::with() { 340 UnlocalizedNumberFormatter result; 341 return result; 342 } 343 344 LocalizedNumberFormatter NumberFormatter::withLocale(const Locale& locale) { 345 return with().locale(locale); 346 } 347 348 UnlocalizedNumberFormatter 349 NumberFormatter::forSkeleton(const UnicodeString& skeleton, UErrorCode& status) { 350 return skeleton::create(skeleton, status); 351 } 352 353 354 template<typename T> using NFS = NumberFormatterSettings<T>; 355 using LNF = LocalizedNumberFormatter; 356 using UNF = UnlocalizedNumberFormatter; 357 358 UnlocalizedNumberFormatter::UnlocalizedNumberFormatter(const UNF& other) 359 : UNF(static_cast<const NFS<UNF>&>(other)) {} 360 361 UnlocalizedNumberFormatter::UnlocalizedNumberFormatter(const NFS<UNF>& other) 362 : NFS<UNF>(other) { 363 // No additional fields to assign 364 } 365 366 // Make default copy constructor call the NumberFormatterSettings copy constructor. 367 UnlocalizedNumberFormatter::UnlocalizedNumberFormatter(UNF&& src) U_NOEXCEPT 368 : UNF(static_cast<NFS<UNF>&&>(src)) {} 369 370 UnlocalizedNumberFormatter::UnlocalizedNumberFormatter(NFS<UNF>&& src) U_NOEXCEPT 371 : NFS<UNF>(std::move(src)) { 372 // No additional fields to assign 373 } 374 375 UnlocalizedNumberFormatter& UnlocalizedNumberFormatter::operator=(const UNF& other) { 376 NFS<UNF>::operator=(static_cast<const NFS<UNF>&>(other)); 377 // No additional fields to assign 378 return *this; 379 } 380 381 UnlocalizedNumberFormatter& UnlocalizedNumberFormatter::operator=(UNF&& src) U_NOEXCEPT { 382 NFS<UNF>::operator=(static_cast<NFS<UNF>&&>(src)); 383 // No additional fields to assign 384 return *this; 385 } 386 387 // Make default copy constructor call the NumberFormatterSettings copy constructor. 388 LocalizedNumberFormatter::LocalizedNumberFormatter(const LNF& other) 389 : LNF(static_cast<const NFS<LNF>&>(other)) {} 390 391 LocalizedNumberFormatter::LocalizedNumberFormatter(const NFS<LNF>& other) 392 : NFS<LNF>(other) { 393 // No additional fields to assign (let call count and compiled formatter reset to defaults) 394 } 395 396 LocalizedNumberFormatter::LocalizedNumberFormatter(LocalizedNumberFormatter&& src) U_NOEXCEPT 397 : LNF(static_cast<NFS<LNF>&&>(src)) {} 398 399 LocalizedNumberFormatter::LocalizedNumberFormatter(NFS<LNF>&& src) U_NOEXCEPT 400 : NFS<LNF>(std::move(src)) { 401 // For the move operators, copy over the compiled formatter. 402 // Note: if the formatter is not compiled, call count information is lost. 403 if (static_cast<LNF&&>(src).fCompiled != nullptr) { 404 lnfMoveHelper(static_cast<LNF&&>(src)); 405 } 406 } 407 408 LocalizedNumberFormatter& LocalizedNumberFormatter::operator=(const LNF& other) { 409 NFS<LNF>::operator=(static_cast<const NFS<LNF>&>(other)); 410 // Reset to default values. 411 clear(); 412 return *this; 413 } 414 415 LocalizedNumberFormatter& LocalizedNumberFormatter::operator=(LNF&& src) U_NOEXCEPT { 416 NFS<LNF>::operator=(static_cast<NFS<LNF>&&>(src)); 417 // For the move operators, copy over the compiled formatter. 418 // Note: if the formatter is not compiled, call count information is lost. 419 if (static_cast<LNF&&>(src).fCompiled != nullptr) { 420 // Formatter is compiled 421 lnfMoveHelper(static_cast<LNF&&>(src)); 422 } else { 423 clear(); 424 } 425 return *this; 426 } 427 428 void LocalizedNumberFormatter::clear() { 429 // Reset to default values. 430 auto* callCount = reinterpret_cast<u_atomic_int32_t*>(fUnsafeCallCount); 431 umtx_storeRelease(*callCount, 0); 432 delete fCompiled; 433 fCompiled = nullptr; 434 } 435 436 void LocalizedNumberFormatter::lnfMoveHelper(LNF&& src) { 437 // Copy over the compiled formatter and set call count to INT32_MIN as in computeCompiled(). 438 // Don't copy the call count directly because doing so requires a loadAcquire/storeRelease. 439 // The bits themselves appear to be platform-dependent, so copying them might not be safe. 440 auto* callCount = reinterpret_cast<u_atomic_int32_t*>(fUnsafeCallCount); 441 umtx_storeRelease(*callCount, INT32_MIN); 442 delete fCompiled; 443 fCompiled = src.fCompiled; 444 // Reset the source object to leave it in a safe state. 445 auto* srcCallCount = reinterpret_cast<u_atomic_int32_t*>(src.fUnsafeCallCount); 446 umtx_storeRelease(*srcCallCount, 0); 447 src.fCompiled = nullptr; 448 } 449 450 451 LocalizedNumberFormatter::~LocalizedNumberFormatter() { 452 delete fCompiled; 453 } 454 455 LocalizedNumberFormatter::LocalizedNumberFormatter(const MacroProps& macros, const Locale& locale) { 456 fMacros = macros; 457 fMacros.locale = locale; 458 } 459 460 LocalizedNumberFormatter::LocalizedNumberFormatter(MacroProps&& macros, const Locale& locale) { 461 fMacros = std::move(macros); 462 fMacros.locale = locale; 463 } 464 465 LocalizedNumberFormatter UnlocalizedNumberFormatter::locale(const Locale& locale) const& { 466 return LocalizedNumberFormatter(fMacros, locale); 467 } 468 469 LocalizedNumberFormatter UnlocalizedNumberFormatter::locale(const Locale& locale)&& { 470 return LocalizedNumberFormatter(std::move(fMacros), locale); 471 } 472 473 SymbolsWrapper::SymbolsWrapper(const SymbolsWrapper& other) { 474 doCopyFrom(other); 475 } 476 477 SymbolsWrapper::SymbolsWrapper(SymbolsWrapper&& src) U_NOEXCEPT { 478 doMoveFrom(std::move(src)); 479 } 480 481 SymbolsWrapper& SymbolsWrapper::operator=(const SymbolsWrapper& other) { 482 if (this == &other) { 483 return *this; 484 } 485 doCleanup(); 486 doCopyFrom(other); 487 return *this; 488 } 489 490 SymbolsWrapper& SymbolsWrapper::operator=(SymbolsWrapper&& src) U_NOEXCEPT { 491 if (this == &src) { 492 return *this; 493 } 494 doCleanup(); 495 doMoveFrom(std::move(src)); 496 return *this; 497 } 498 499 SymbolsWrapper::~SymbolsWrapper() { 500 doCleanup(); 501 } 502 503 void SymbolsWrapper::setTo(const DecimalFormatSymbols& dfs) { 504 doCleanup(); 505 fType = SYMPTR_DFS; 506 fPtr.dfs = new DecimalFormatSymbols(dfs); 507 } 508 509 void SymbolsWrapper::setTo(const NumberingSystem* ns) { 510 doCleanup(); 511 fType = SYMPTR_NS; 512 fPtr.ns = ns; 513 } 514 515 void SymbolsWrapper::doCopyFrom(const SymbolsWrapper& other) { 516 fType = other.fType; 517 switch (fType) { 518 case SYMPTR_NONE: 519 // No action necessary 520 break; 521 case SYMPTR_DFS: 522 // Memory allocation failures are exposed in copyErrorTo() 523 if (other.fPtr.dfs != nullptr) { 524 fPtr.dfs = new DecimalFormatSymbols(*other.fPtr.dfs); 525 } else { 526 fPtr.dfs = nullptr; 527 } 528 break; 529 case SYMPTR_NS: 530 // Memory allocation failures are exposed in copyErrorTo() 531 if (other.fPtr.ns != nullptr) { 532 fPtr.ns = new NumberingSystem(*other.fPtr.ns); 533 } else { 534 fPtr.ns = nullptr; 535 } 536 break; 537 } 538 } 539 540 void SymbolsWrapper::doMoveFrom(SymbolsWrapper&& src) { 541 fType = src.fType; 542 switch (fType) { 543 case SYMPTR_NONE: 544 // No action necessary 545 break; 546 case SYMPTR_DFS: 547 fPtr.dfs = src.fPtr.dfs; 548 src.fPtr.dfs = nullptr; 549 break; 550 case SYMPTR_NS: 551 fPtr.ns = src.fPtr.ns; 552 src.fPtr.ns = nullptr; 553 break; 554 } 555 } 556 557 void SymbolsWrapper::doCleanup() { 558 switch (fType) { 559 case SYMPTR_NONE: 560 // No action necessary 561 break; 562 case SYMPTR_DFS: 563 delete fPtr.dfs; 564 break; 565 case SYMPTR_NS: 566 delete fPtr.ns; 567 break; 568 } 569 } 570 571 bool SymbolsWrapper::isDecimalFormatSymbols() const { 572 return fType == SYMPTR_DFS; 573 } 574 575 bool SymbolsWrapper::isNumberingSystem() const { 576 return fType == SYMPTR_NS; 577 } 578 579 const DecimalFormatSymbols* SymbolsWrapper::getDecimalFormatSymbols() const { 580 U_ASSERT(fType == SYMPTR_DFS); 581 return fPtr.dfs; 582 } 583 584 const NumberingSystem* SymbolsWrapper::getNumberingSystem() const { 585 U_ASSERT(fType == SYMPTR_NS); 586 return fPtr.ns; 587 } 588 589 590 FormattedNumber LocalizedNumberFormatter::formatInt(int64_t value, UErrorCode& status) const { 591 if (U_FAILURE(status)) { return FormattedNumber(U_ILLEGAL_ARGUMENT_ERROR); } 592 auto results = new UFormattedNumberData(); 593 if (results == nullptr) { 594 status = U_MEMORY_ALLOCATION_ERROR; 595 return FormattedNumber(status); 596 } 597 results->quantity.setToLong(value); 598 formatImpl(results, status); 599 600 // Do not save the results object if we encountered a failure. 601 if (U_SUCCESS(status)) { 602 return FormattedNumber(results); 603 } else { 604 delete results; 605 return FormattedNumber(status); 606 } 607 } 608 609 FormattedNumber LocalizedNumberFormatter::formatDouble(double value, UErrorCode& status) const { 610 if (U_FAILURE(status)) { return FormattedNumber(U_ILLEGAL_ARGUMENT_ERROR); } 611 auto results = new UFormattedNumberData(); 612 if (results == nullptr) { 613 status = U_MEMORY_ALLOCATION_ERROR; 614 return FormattedNumber(status); 615 } 616 results->quantity.setToDouble(value); 617 formatImpl(results, status); 618 619 // Do not save the results object if we encountered a failure. 620 if (U_SUCCESS(status)) { 621 return FormattedNumber(results); 622 } else { 623 delete results; 624 return FormattedNumber(status); 625 } 626 } 627 628 FormattedNumber LocalizedNumberFormatter::formatDecimal(StringPiece value, UErrorCode& status) const { 629 if (U_FAILURE(status)) { return FormattedNumber(U_ILLEGAL_ARGUMENT_ERROR); } 630 auto results = new UFormattedNumberData(); 631 if (results == nullptr) { 632 status = U_MEMORY_ALLOCATION_ERROR; 633 return FormattedNumber(status); 634 } 635 results->quantity.setToDecNumber(value, status); 636 formatImpl(results, status); 637 638 // Do not save the results object if we encountered a failure. 639 if (U_SUCCESS(status)) { 640 return FormattedNumber(results); 641 } else { 642 delete results; 643 return FormattedNumber(status); 644 } 645 } 646 647 FormattedNumber 648 LocalizedNumberFormatter::formatDecimalQuantity(const DecimalQuantity& dq, UErrorCode& status) const { 649 if (U_FAILURE(status)) { return FormattedNumber(U_ILLEGAL_ARGUMENT_ERROR); } 650 auto results = new UFormattedNumberData(); 651 if (results == nullptr) { 652 status = U_MEMORY_ALLOCATION_ERROR; 653 return FormattedNumber(status); 654 } 655 results->quantity = dq; 656 formatImpl(results, status); 657 658 // Do not save the results object if we encountered a failure. 659 if (U_SUCCESS(status)) { 660 return FormattedNumber(results); 661 } else { 662 delete results; 663 return FormattedNumber(status); 664 } 665 } 666 667 void LocalizedNumberFormatter::formatImpl(impl::UFormattedNumberData* results, UErrorCode& status) const { 668 if (computeCompiled(status)) { 669 fCompiled->format(results->quantity, results->string, status); 670 } else { 671 NumberFormatterImpl::formatStatic(fMacros, results->quantity, results->string, status); 672 } 673 } 674 675 void LocalizedNumberFormatter::getAffixImpl(bool isPrefix, bool isNegative, UnicodeString& result, 676 UErrorCode& status) const { 677 NumberStringBuilder string; 678 auto signum = static_cast<int8_t>(isNegative ? -1 : 1); 679 // Always return affixes for plural form OTHER. 680 static const StandardPlural::Form plural = StandardPlural::OTHER; 681 int32_t prefixLength; 682 if (computeCompiled(status)) { 683 prefixLength = fCompiled->getPrefixSuffix(signum, plural, string, status); 684 } else { 685 prefixLength = NumberFormatterImpl::getPrefixSuffixStatic(fMacros, signum, plural, string, status); 686 } 687 result.remove(); 688 if (isPrefix) { 689 result.append(string.toTempUnicodeString().tempSubStringBetween(0, prefixLength)); 690 } else { 691 result.append(string.toTempUnicodeString().tempSubStringBetween(prefixLength, string.length())); 692 } 693 } 694 695 bool LocalizedNumberFormatter::computeCompiled(UErrorCode& status) const { 696 // fUnsafeCallCount contains memory to be interpreted as an atomic int, most commonly 697 // std::atomic<int32_t>. Since the type of atomic int is platform-dependent, we cast the 698 // bytes in fUnsafeCallCount to u_atomic_int32_t, a typedef for the platform-dependent 699 // atomic int type defined in umutex.h. 700 static_assert( 701 sizeof(u_atomic_int32_t) <= sizeof(fUnsafeCallCount), 702 "Atomic integer size on this platform exceeds the size allocated by fUnsafeCallCount"); 703 auto* callCount = reinterpret_cast<u_atomic_int32_t*>( 704 const_cast<LocalizedNumberFormatter*>(this)->fUnsafeCallCount); 705 706 // A positive value in the atomic int indicates that the data structure is not yet ready; 707 // a negative value indicates that it is ready. If, after the increment, the atomic int 708 // is exactly threshold, then it is the current thread's job to build the data structure. 709 // Note: We set the callCount to INT32_MIN so that if another thread proceeds to increment 710 // the atomic int, the value remains below zero. 711 int32_t currentCount = umtx_loadAcquire(*callCount); 712 if (0 <= currentCount && currentCount <= fMacros.threshold && fMacros.threshold > 0) { 713 currentCount = umtx_atomic_inc(callCount); 714 } 715 716 if (currentCount == fMacros.threshold && fMacros.threshold > 0) { 717 // Build the data structure and then use it (slow to fast path). 718 const NumberFormatterImpl* compiled = new NumberFormatterImpl(fMacros, status); 719 if (compiled == nullptr) { 720 status = U_MEMORY_ALLOCATION_ERROR; 721 return false; 722 } 723 U_ASSERT(fCompiled == nullptr); 724 const_cast<LocalizedNumberFormatter*>(this)->fCompiled = compiled; 725 umtx_storeRelease(*callCount, INT32_MIN); 726 return true; 727 } else if (currentCount < 0) { 728 // The data structure is already built; use it (fast path). 729 U_ASSERT(fCompiled != nullptr); 730 return true; 731 } else { 732 // Format the number without building the data structure (slow path). 733 return false; 734 } 735 } 736 737 const impl::NumberFormatterImpl* LocalizedNumberFormatter::getCompiled() const { 738 return fCompiled; 739 } 740 741 int32_t LocalizedNumberFormatter::getCallCount() const { 742 auto* callCount = reinterpret_cast<u_atomic_int32_t*>( 743 const_cast<LocalizedNumberFormatter*>(this)->fUnsafeCallCount); 744 return umtx_loadAcquire(*callCount); 745 } 746 747 Format* LocalizedNumberFormatter::toFormat(UErrorCode& status) const { 748 LocalPointer<LocalizedNumberFormatterAsFormat> retval( 749 new LocalizedNumberFormatterAsFormat(*this, fMacros.locale), status); 750 return retval.orphan(); 751 } 752 753 754 FormattedNumber::FormattedNumber(FormattedNumber&& src) U_NOEXCEPT 755 : fResults(src.fResults), fErrorCode(src.fErrorCode) { 756 // Disown src.fResults to prevent double-deletion 757 src.fResults = nullptr; 758 src.fErrorCode = U_INVALID_STATE_ERROR; 759 } 760 761 FormattedNumber& FormattedNumber::operator=(FormattedNumber&& src) U_NOEXCEPT { 762 delete fResults; 763 fResults = src.fResults; 764 fErrorCode = src.fErrorCode; 765 // Disown src.fResults to prevent double-deletion 766 src.fResults = nullptr; 767 src.fErrorCode = U_INVALID_STATE_ERROR; 768 return *this; 769 } 770 771 UnicodeString FormattedNumber::toString() const { 772 UErrorCode localStatus = U_ZERO_ERROR; 773 return toString(localStatus); 774 } 775 776 UnicodeString FormattedNumber::toString(UErrorCode& status) const { 777 if (U_FAILURE(status)) { 778 return ICU_Utility::makeBogusString(); 779 } 780 if (fResults == nullptr) { 781 status = fErrorCode; 782 return ICU_Utility::makeBogusString(); 783 } 784 return fResults->string.toUnicodeString(); 785 } 786 787 Appendable& FormattedNumber::appendTo(Appendable& appendable) { 788 UErrorCode localStatus = U_ZERO_ERROR; 789 return appendTo(appendable, localStatus); 790 } 791 792 Appendable& FormattedNumber::appendTo(Appendable& appendable, UErrorCode& status) const { 793 if (U_FAILURE(status)) { 794 return appendable; 795 } 796 if (fResults == nullptr) { 797 status = fErrorCode; 798 return appendable; 799 } 800 appendable.appendString(fResults->string.chars(), fResults->string.length()); 801 return appendable; 802 } 803 804 void FormattedNumber::populateFieldPosition(FieldPosition& fieldPosition, UErrorCode& status) { 805 if (U_FAILURE(status)) { 806 return; 807 } 808 if (fResults == nullptr) { 809 status = fErrorCode; 810 return; 811 } 812 // in case any users were depending on the old behavior: 813 fieldPosition.setBeginIndex(0); 814 fieldPosition.setEndIndex(0); 815 fResults->string.nextFieldPosition(fieldPosition, status); 816 } 817 818 UBool FormattedNumber::nextFieldPosition(FieldPosition& fieldPosition, UErrorCode& status) const { 819 if (U_FAILURE(status)) { 820 return FALSE; 821 } 822 if (fResults == nullptr) { 823 status = fErrorCode; 824 return FALSE; 825 } 826 // NOTE: MSVC sometimes complains when implicitly converting between bool and UBool 827 return fResults->string.nextFieldPosition(fieldPosition, status) ? TRUE : FALSE; 828 } 829 830 void FormattedNumber::populateFieldPositionIterator(FieldPositionIterator& iterator, UErrorCode& status) { 831 getAllFieldPositions(iterator, status); 832 } 833 834 void FormattedNumber::getAllFieldPositions(FieldPositionIterator& iterator, UErrorCode& status) const { 835 FieldPositionIteratorHandler fpih(&iterator, status); 836 getAllFieldPositionsImpl(fpih, status); 837 } 838 839 void FormattedNumber::getAllFieldPositionsImpl(FieldPositionIteratorHandler& fpih, 840 UErrorCode& status) const { 841 if (U_FAILURE(status)) { 842 return; 843 } 844 if (fResults == nullptr) { 845 status = fErrorCode; 846 return; 847 } 848 fResults->string.getAllFieldPositions(fpih, status); 849 } 850 851 void FormattedNumber::getDecimalQuantity(DecimalQuantity& output, UErrorCode& status) const { 852 if (U_FAILURE(status)) { 853 return; 854 } 855 if (fResults == nullptr) { 856 status = fErrorCode; 857 return; 858 } 859 output = fResults->quantity; 860 } 861 862 FormattedNumber::~FormattedNumber() { 863 delete fResults; 864 } 865 866 #endif /* #if !UCONFIG_NO_FORMATTING */ 867