number_fluent.cpp (25953B)
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_utils.h" 15 #include "number_utypes.h" 16 #include "number_mapper.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 #if (U_PF_WINDOWS <= U_PLATFORM && U_PLATFORM <= U_PF_CYGWIN) && defined(_MSC_VER) 25 // Ignore MSVC warning 4661. This is generated for NumberFormatterSettings<>::toSkeleton() as this method 26 // is defined elsewhere (in number_skeletons.cpp). The compiler is warning that the explicit template instantiation 27 // inside this single translation unit (CPP file) is incomplete, and thus it isn't sure if the template class is 28 // fully defined. However, since each translation unit explicitly instantiates all the necessary template classes, 29 // they will all be passed to the linker, and the linker will still find and export all the class members. 30 #pragma warning(push) 31 #pragma warning(disable: 4661) 32 #endif 33 34 template<typename Derived> 35 Derived NumberFormatterSettings<Derived>::notation(const Notation& notation) const& { 36 Derived copy(*this); 37 // NOTE: Slicing is OK. 38 copy.fMacros.notation = notation; 39 return copy; 40 } 41 42 template<typename Derived> 43 Derived NumberFormatterSettings<Derived>::notation(const Notation& notation)&& { 44 Derived move(std::move(*this)); 45 // NOTE: Slicing is OK. 46 move.fMacros.notation = notation; 47 return move; 48 } 49 50 template<typename Derived> 51 Derived NumberFormatterSettings<Derived>::unit(const icu::MeasureUnit& unit) const& { 52 Derived copy(*this); 53 // NOTE: Slicing occurs here. However, CurrencyUnit can be restored from MeasureUnit. 54 // TimeUnit may be affected, but TimeUnit is not as relevant to number formatting. 55 copy.fMacros.unit = unit; 56 return copy; 57 } 58 59 template<typename Derived> 60 Derived NumberFormatterSettings<Derived>::unit(const icu::MeasureUnit& unit)&& { 61 Derived move(std::move(*this)); 62 // See comments above about slicing. 63 move.fMacros.unit = unit; 64 return move; 65 } 66 67 template<typename Derived> 68 Derived NumberFormatterSettings<Derived>::adoptUnit(icu::MeasureUnit* unit) const& { 69 Derived copy(*this); 70 // Just move the unit into the MacroProps by value, and delete it since we have ownership. 71 // NOTE: Slicing occurs here. However, CurrencyUnit can be restored from MeasureUnit. 72 // TimeUnit may be affected, but TimeUnit is not as relevant to number formatting. 73 if (unit != nullptr) { 74 // TODO: On nullptr, reset to default value? 75 copy.fMacros.unit = std::move(*unit); 76 delete unit; 77 } 78 return copy; 79 } 80 81 template<typename Derived> 82 Derived NumberFormatterSettings<Derived>::adoptUnit(icu::MeasureUnit* unit)&& { 83 Derived move(std::move(*this)); 84 // See comments above about slicing and ownership. 85 if (unit != nullptr) { 86 // TODO: On nullptr, reset to default value? 87 move.fMacros.unit = std::move(*unit); 88 delete unit; 89 } 90 return move; 91 } 92 93 template<typename Derived> 94 Derived NumberFormatterSettings<Derived>::perUnit(const icu::MeasureUnit& perUnit) const& { 95 Derived copy(*this); 96 // See comments above about slicing. 97 copy.fMacros.perUnit = perUnit; 98 return copy; 99 } 100 101 template<typename Derived> 102 Derived NumberFormatterSettings<Derived>::perUnit(const icu::MeasureUnit& perUnit)&& { 103 Derived move(std::move(*this)); 104 // See comments above about slicing. 105 move.fMacros.perUnit = perUnit; 106 return move; 107 } 108 109 template<typename Derived> 110 Derived NumberFormatterSettings<Derived>::adoptPerUnit(icu::MeasureUnit* perUnit) const& { 111 Derived copy(*this); 112 // See comments above about slicing and ownership. 113 if (perUnit != nullptr) { 114 // TODO: On nullptr, reset to default value? 115 copy.fMacros.perUnit = std::move(*perUnit); 116 delete perUnit; 117 } 118 return copy; 119 } 120 121 template<typename Derived> 122 Derived NumberFormatterSettings<Derived>::adoptPerUnit(icu::MeasureUnit* perUnit)&& { 123 Derived move(std::move(*this)); 124 // See comments above about slicing and ownership. 125 if (perUnit != nullptr) { 126 // TODO: On nullptr, reset to default value? 127 move.fMacros.perUnit = std::move(*perUnit); 128 delete perUnit; 129 } 130 return move; 131 } 132 133 template<typename Derived> 134 Derived NumberFormatterSettings<Derived>::precision(const Precision& precision) const& { 135 Derived copy(*this); 136 // NOTE: Slicing is OK. 137 copy.fMacros.precision = precision; 138 return copy; 139 } 140 141 template<typename Derived> 142 Derived NumberFormatterSettings<Derived>::precision(const Precision& precision)&& { 143 Derived move(std::move(*this)); 144 // NOTE: Slicing is OK. 145 move.fMacros.precision = precision; 146 return move; 147 } 148 149 template<typename Derived> 150 Derived NumberFormatterSettings<Derived>::roundingMode(UNumberFormatRoundingMode roundingMode) const& { 151 Derived copy(*this); 152 copy.fMacros.roundingMode = roundingMode; 153 return copy; 154 } 155 156 template<typename Derived> 157 Derived NumberFormatterSettings<Derived>::roundingMode(UNumberFormatRoundingMode roundingMode)&& { 158 Derived move(std::move(*this)); 159 move.fMacros.roundingMode = roundingMode; 160 return move; 161 } 162 163 template<typename Derived> 164 Derived NumberFormatterSettings<Derived>::grouping(UNumberGroupingStrategy strategy) const& { 165 Derived copy(*this); 166 // NOTE: This is slightly different than how the setting is stored in Java 167 // because we want to put it on the stack. 168 copy.fMacros.grouper = Grouper::forStrategy(strategy); 169 return copy; 170 } 171 172 template<typename Derived> 173 Derived NumberFormatterSettings<Derived>::grouping(UNumberGroupingStrategy strategy)&& { 174 Derived move(std::move(*this)); 175 move.fMacros.grouper = Grouper::forStrategy(strategy); 176 return move; 177 } 178 179 template<typename Derived> 180 Derived NumberFormatterSettings<Derived>::integerWidth(const IntegerWidth& style) const& { 181 Derived copy(*this); 182 copy.fMacros.integerWidth = style; 183 return copy; 184 } 185 186 template<typename Derived> 187 Derived NumberFormatterSettings<Derived>::integerWidth(const IntegerWidth& style)&& { 188 Derived move(std::move(*this)); 189 move.fMacros.integerWidth = style; 190 return move; 191 } 192 193 template<typename Derived> 194 Derived NumberFormatterSettings<Derived>::symbols(const DecimalFormatSymbols& symbols) const& { 195 Derived copy(*this); 196 copy.fMacros.symbols.setTo(symbols); 197 return copy; 198 } 199 200 template<typename Derived> 201 Derived NumberFormatterSettings<Derived>::symbols(const DecimalFormatSymbols& symbols)&& { 202 Derived move(std::move(*this)); 203 move.fMacros.symbols.setTo(symbols); 204 return move; 205 } 206 207 template<typename Derived> 208 Derived NumberFormatterSettings<Derived>::adoptSymbols(NumberingSystem* ns) const& { 209 Derived copy(*this); 210 copy.fMacros.symbols.setTo(ns); 211 return copy; 212 } 213 214 template<typename Derived> 215 Derived NumberFormatterSettings<Derived>::adoptSymbols(NumberingSystem* ns)&& { 216 Derived move(std::move(*this)); 217 move.fMacros.symbols.setTo(ns); 218 return move; 219 } 220 221 template<typename Derived> 222 Derived NumberFormatterSettings<Derived>::unitWidth(UNumberUnitWidth width) const& { 223 Derived copy(*this); 224 copy.fMacros.unitWidth = width; 225 return copy; 226 } 227 228 template<typename Derived> 229 Derived NumberFormatterSettings<Derived>::unitWidth(UNumberUnitWidth width)&& { 230 Derived move(std::move(*this)); 231 move.fMacros.unitWidth = width; 232 return move; 233 } 234 235 template<typename Derived> 236 Derived NumberFormatterSettings<Derived>::sign(UNumberSignDisplay style) const& { 237 Derived copy(*this); 238 copy.fMacros.sign = style; 239 return copy; 240 } 241 242 template<typename Derived> 243 Derived NumberFormatterSettings<Derived>::sign(UNumberSignDisplay style)&& { 244 Derived move(std::move(*this)); 245 move.fMacros.sign = style; 246 return move; 247 } 248 249 template<typename Derived> 250 Derived NumberFormatterSettings<Derived>::decimal(UNumberDecimalSeparatorDisplay style) const& { 251 Derived copy(*this); 252 copy.fMacros.decimal = style; 253 return copy; 254 } 255 256 template<typename Derived> 257 Derived NumberFormatterSettings<Derived>::decimal(UNumberDecimalSeparatorDisplay style)&& { 258 Derived move(std::move(*this)); 259 move.fMacros.decimal = style; 260 return move; 261 } 262 263 template<typename Derived> 264 Derived NumberFormatterSettings<Derived>::scale(const Scale& scale) const& { 265 Derived copy(*this); 266 copy.fMacros.scale = scale; 267 return copy; 268 } 269 270 template<typename Derived> 271 Derived NumberFormatterSettings<Derived>::scale(const Scale& scale)&& { 272 Derived move(std::move(*this)); 273 move.fMacros.scale = scale; 274 return move; 275 } 276 277 template<typename Derived> 278 Derived NumberFormatterSettings<Derived>::usage(const StringPiece usage) const& { 279 Derived copy(*this); 280 copy.fMacros.usage.set(usage); 281 return copy; 282 } 283 284 template<typename Derived> 285 Derived NumberFormatterSettings<Derived>::usage(const StringPiece usage)&& { 286 Derived move(std::move(*this)); 287 move.fMacros.usage.set(usage); 288 return move; 289 } 290 291 template <typename Derived> 292 Derived NumberFormatterSettings<Derived>::displayOptions(const DisplayOptions &displayOptions) const & { 293 Derived copy(*this); 294 // `displayCase` does not recognise the `undefined` 295 if (displayOptions.getGrammaticalCase() == UDISPOPT_GRAMMATICAL_CASE_UNDEFINED) { 296 copy.fMacros.unitDisplayCase.set(nullptr); 297 return copy; 298 } 299 300 copy.fMacros.unitDisplayCase.set( 301 udispopt_getGrammaticalCaseIdentifier(displayOptions.getGrammaticalCase())); 302 return copy; 303 } 304 305 template <typename Derived> 306 Derived NumberFormatterSettings<Derived>::displayOptions(const DisplayOptions &displayOptions) && { 307 Derived move(std::move(*this)); 308 // `displayCase` does not recognise the `undefined` 309 if (displayOptions.getGrammaticalCase() == UDISPOPT_GRAMMATICAL_CASE_UNDEFINED) { 310 move.fMacros.unitDisplayCase.set(nullptr); 311 return move; 312 } 313 314 move.fMacros.unitDisplayCase.set( 315 udispopt_getGrammaticalCaseIdentifier(displayOptions.getGrammaticalCase())); 316 return move; 317 } 318 319 template<typename Derived> 320 Derived NumberFormatterSettings<Derived>::unitDisplayCase(const StringPiece unitDisplayCase) const& { 321 Derived copy(*this); 322 copy.fMacros.unitDisplayCase.set(unitDisplayCase); 323 return copy; 324 } 325 326 template<typename Derived> 327 Derived NumberFormatterSettings<Derived>::unitDisplayCase(const StringPiece unitDisplayCase)&& { 328 Derived move(std::move(*this)); 329 move.fMacros.unitDisplayCase.set(unitDisplayCase); 330 return move; 331 } 332 333 template<typename Derived> 334 Derived NumberFormatterSettings<Derived>::padding(const Padder& padder) const& { 335 Derived copy(*this); 336 copy.fMacros.padder = padder; 337 return copy; 338 } 339 340 template<typename Derived> 341 Derived NumberFormatterSettings<Derived>::padding(const Padder& padder)&& { 342 Derived move(std::move(*this)); 343 move.fMacros.padder = padder; 344 return move; 345 } 346 347 template<typename Derived> 348 Derived NumberFormatterSettings<Derived>::threshold(int32_t threshold) const& { 349 Derived copy(*this); 350 copy.fMacros.threshold = threshold; 351 return copy; 352 } 353 354 template<typename Derived> 355 Derived NumberFormatterSettings<Derived>::threshold(int32_t threshold)&& { 356 Derived move(std::move(*this)); 357 move.fMacros.threshold = threshold; 358 return move; 359 } 360 361 template<typename Derived> 362 Derived NumberFormatterSettings<Derived>::macros(const impl::MacroProps& macros) const& { 363 Derived copy(*this); 364 copy.fMacros = macros; 365 return copy; 366 } 367 368 template<typename Derived> 369 Derived NumberFormatterSettings<Derived>::macros(const impl::MacroProps& macros)&& { 370 Derived move(std::move(*this)); 371 move.fMacros = macros; 372 return move; 373 } 374 375 template<typename Derived> 376 Derived NumberFormatterSettings<Derived>::macros(impl::MacroProps&& macros) const& { 377 Derived copy(*this); 378 copy.fMacros = std::move(macros); 379 return copy; 380 } 381 382 template<typename Derived> 383 Derived NumberFormatterSettings<Derived>::macros(impl::MacroProps&& macros)&& { 384 Derived move(std::move(*this)); 385 move.fMacros = std::move(macros); 386 return move; 387 } 388 389 // Note: toSkeleton defined in number_skeletons.cpp 390 391 template<typename Derived> 392 LocalPointer<Derived> NumberFormatterSettings<Derived>::clone() const & { 393 return LocalPointer<Derived>(new Derived(*this)); 394 } 395 396 template<typename Derived> 397 LocalPointer<Derived> NumberFormatterSettings<Derived>::clone() && { 398 return LocalPointer<Derived>(new Derived(std::move(*this))); 399 } 400 401 // Declare all classes that implement NumberFormatterSettings 402 // See https://stackoverflow.com/a/495056/1407170 403 template 404 class icu::number::NumberFormatterSettings<icu::number::UnlocalizedNumberFormatter>; 405 template 406 class icu::number::NumberFormatterSettings<icu::number::LocalizedNumberFormatter>; 407 408 409 UnlocalizedNumberFormatter NumberFormatter::with() { 410 UnlocalizedNumberFormatter result; 411 return result; 412 } 413 414 LocalizedNumberFormatter NumberFormatter::withLocale(const Locale& locale) { 415 return with().locale(locale); 416 } 417 418 // Note: forSkeleton defined in number_skeletons.cpp 419 420 421 template<typename T> using NFS = NumberFormatterSettings<T>; 422 using LNF = LocalizedNumberFormatter; 423 using UNF = UnlocalizedNumberFormatter; 424 425 UnlocalizedNumberFormatter::UnlocalizedNumberFormatter(const UNF& other) 426 : UNF(static_cast<const NFS<UNF>&>(other)) {} 427 428 UnlocalizedNumberFormatter::UnlocalizedNumberFormatter(const NFS<UNF>& other) 429 : NFS<UNF>(other) { 430 // No additional fields to assign 431 } 432 433 UnlocalizedNumberFormatter::UnlocalizedNumberFormatter(const impl::MacroProps ¯os) { 434 fMacros = macros; 435 } 436 437 UnlocalizedNumberFormatter::UnlocalizedNumberFormatter(impl::MacroProps &¯os) { 438 fMacros = macros; 439 } 440 441 // Make default copy constructor call the NumberFormatterSettings copy constructor. 442 UnlocalizedNumberFormatter::UnlocalizedNumberFormatter(UNF&& src) noexcept 443 : UNF(static_cast<NFS<UNF>&&>(src)) {} 444 445 UnlocalizedNumberFormatter::UnlocalizedNumberFormatter(NFS<UNF>&& src) noexcept 446 : NFS<UNF>(std::move(src)) { 447 // No additional fields to assign 448 } 449 450 UnlocalizedNumberFormatter& UnlocalizedNumberFormatter::operator=(const UNF& other) { 451 NFS<UNF>::operator=(static_cast<const NFS<UNF>&>(other)); 452 // No additional fields to assign 453 return *this; 454 } 455 456 UnlocalizedNumberFormatter& UnlocalizedNumberFormatter::operator=(UNF&& src) noexcept { 457 NFS<UNF>::operator=(static_cast<NFS<UNF>&&>(src)); 458 // No additional fields to assign 459 return *this; 460 } 461 462 // Make default copy constructor call the NumberFormatterSettings copy constructor. 463 LocalizedNumberFormatter::LocalizedNumberFormatter(const LNF& other) 464 : LNF(static_cast<const NFS<LNF>&>(other)) {} 465 466 LocalizedNumberFormatter::LocalizedNumberFormatter(const NFS<LNF>& other) 467 : NFS<LNF>(other) { 468 UErrorCode localStatus = U_ZERO_ERROR; // Can't bubble up the error 469 lnfCopyHelper(static_cast<const LNF&>(other), localStatus); 470 } 471 472 LocalizedNumberFormatter::LocalizedNumberFormatter(LocalizedNumberFormatter&& src) noexcept 473 : LNF(static_cast<NFS<LNF>&&>(src)) {} 474 475 LocalizedNumberFormatter::LocalizedNumberFormatter(NFS<LNF>&& src) noexcept 476 : NFS<LNF>(std::move(src)) { 477 lnfMoveHelper(std::move(static_cast<LNF&&>(src))); 478 } 479 480 LocalizedNumberFormatter& LocalizedNumberFormatter::operator=(const LNF& other) { 481 if (this == &other) { return *this; } // self-assignment: no-op 482 NFS<LNF>::operator=(static_cast<const NFS<LNF>&>(other)); 483 UErrorCode localStatus = U_ZERO_ERROR; // Can't bubble up the error 484 lnfCopyHelper(other, localStatus); 485 return *this; 486 } 487 488 LocalizedNumberFormatter& LocalizedNumberFormatter::operator=(LNF&& src) noexcept { 489 NFS<LNF>::operator=(static_cast<NFS<LNF>&&>(src)); 490 lnfMoveHelper(std::move(src)); 491 return *this; 492 } 493 494 void LocalizedNumberFormatter::resetCompiled() { 495 auto* callCount = reinterpret_cast<u_atomic_int32_t*>(fUnsafeCallCount); 496 umtx_storeRelease(*callCount, 0); 497 fCompiled = nullptr; 498 } 499 500 void LocalizedNumberFormatter::lnfMoveHelper(LNF&& src) { 501 // Copy over the compiled formatter and set call count to INT32_MIN as in computeCompiled(). 502 // Don't copy the call count directly because doing so requires a loadAcquire/storeRelease. 503 // The bits themselves appear to be platform-dependent, so copying them might not be safe. 504 delete fCompiled; 505 if (src.fCompiled != nullptr) { 506 auto* callCount = reinterpret_cast<u_atomic_int32_t*>(fUnsafeCallCount); 507 umtx_storeRelease(*callCount, INT32_MIN); 508 fCompiled = src.fCompiled; 509 // Reset the source object to leave it in a safe state. 510 src.resetCompiled(); 511 } else { 512 resetCompiled(); 513 } 514 515 // Unconditionally move the warehouse 516 delete fWarehouse; 517 fWarehouse = src.fWarehouse; 518 src.fWarehouse = nullptr; 519 } 520 521 void LocalizedNumberFormatter::lnfCopyHelper(const LNF&, UErrorCode& status) { 522 // When copying, always reset the compiled formatter. 523 delete fCompiled; 524 resetCompiled(); 525 526 // If MacroProps has a reference to AffixPatternProvider, we need to copy it. 527 // If MacroProps has a reference to PluralRules, copy that one, too. 528 delete fWarehouse; 529 if (fMacros.affixProvider || fMacros.rules) { 530 LocalPointer<DecimalFormatWarehouse> warehouse(new DecimalFormatWarehouse(), status); 531 if (U_FAILURE(status)) { 532 fWarehouse = nullptr; 533 return; 534 } 535 if (fMacros.affixProvider) { 536 warehouse->affixProvider.setTo(fMacros.affixProvider, status); 537 fMacros.affixProvider = &warehouse->affixProvider.get(); 538 } 539 if (fMacros.rules) { 540 warehouse->rules.adoptInsteadAndCheckErrorCode( 541 new PluralRules(*fMacros.rules), status); 542 fMacros.rules = warehouse->rules.getAlias(); 543 } 544 fWarehouse = warehouse.orphan(); 545 } else { 546 fWarehouse = nullptr; 547 } 548 } 549 550 551 LocalizedNumberFormatter::~LocalizedNumberFormatter() { 552 delete fCompiled; 553 delete fWarehouse; 554 } 555 556 LocalizedNumberFormatter::LocalizedNumberFormatter(const MacroProps& macros, const Locale& locale) { 557 fMacros = macros; 558 fMacros.locale = locale; 559 } 560 561 LocalizedNumberFormatter::LocalizedNumberFormatter(MacroProps&& macros, const Locale& locale) { 562 fMacros = std::move(macros); 563 fMacros.locale = locale; 564 } 565 566 LocalizedNumberFormatter UnlocalizedNumberFormatter::locale(const Locale& locale) const& { 567 return LocalizedNumberFormatter(fMacros, locale); 568 } 569 570 LocalizedNumberFormatter UnlocalizedNumberFormatter::locale(const Locale& locale)&& { 571 return LocalizedNumberFormatter(std::move(fMacros), locale); 572 } 573 574 FormattedNumber LocalizedNumberFormatter::formatInt(int64_t value, UErrorCode& status) const { 575 if (U_FAILURE(status)) { return FormattedNumber(U_ILLEGAL_ARGUMENT_ERROR); } 576 auto* results = new UFormattedNumberData(); 577 if (results == nullptr) { 578 status = U_MEMORY_ALLOCATION_ERROR; 579 return FormattedNumber(status); 580 } 581 results->quantity.setToLong(value); 582 formatImpl(results, status); 583 584 // Do not save the results object if we encountered a failure. 585 if (U_SUCCESS(status)) { 586 return FormattedNumber(results); 587 } else { 588 delete results; 589 return FormattedNumber(status); 590 } 591 } 592 593 FormattedNumber LocalizedNumberFormatter::formatDouble(double value, UErrorCode& status) const { 594 if (U_FAILURE(status)) { return FormattedNumber(U_ILLEGAL_ARGUMENT_ERROR); } 595 auto* results = new UFormattedNumberData(); 596 if (results == nullptr) { 597 status = U_MEMORY_ALLOCATION_ERROR; 598 return FormattedNumber(status); 599 } 600 results->quantity.setToDouble(value); 601 formatImpl(results, status); 602 603 // Do not save the results object if we encountered a failure. 604 if (U_SUCCESS(status)) { 605 return FormattedNumber(results); 606 } else { 607 delete results; 608 return FormattedNumber(status); 609 } 610 } 611 612 FormattedNumber LocalizedNumberFormatter::formatDecimal(StringPiece value, UErrorCode& status) const { 613 if (U_FAILURE(status)) { return FormattedNumber(U_ILLEGAL_ARGUMENT_ERROR); } 614 auto* results = new UFormattedNumberData(); 615 if (results == nullptr) { 616 status = U_MEMORY_ALLOCATION_ERROR; 617 return FormattedNumber(status); 618 } 619 results->quantity.setToDecNumber(value, status); 620 formatImpl(results, status); 621 622 // Do not save the results object if we encountered a failure. 623 if (U_SUCCESS(status)) { 624 return FormattedNumber(results); 625 } else { 626 delete results; 627 return FormattedNumber(status); 628 } 629 } 630 631 FormattedNumber 632 LocalizedNumberFormatter::formatDecimalQuantity(const DecimalQuantity& dq, UErrorCode& status) const { 633 if (U_FAILURE(status)) { return FormattedNumber(U_ILLEGAL_ARGUMENT_ERROR); } 634 auto* results = new UFormattedNumberData(); 635 if (results == nullptr) { 636 status = U_MEMORY_ALLOCATION_ERROR; 637 return FormattedNumber(status); 638 } 639 results->quantity = dq; 640 formatImpl(results, status); 641 642 // Do not save the results object if we encountered a failure. 643 if (U_SUCCESS(status)) { 644 return FormattedNumber(results); 645 } else { 646 delete results; 647 return FormattedNumber(status); 648 } 649 } 650 651 void LocalizedNumberFormatter::formatImpl(impl::UFormattedNumberData* results, UErrorCode& status) const { 652 if (computeCompiled(status)) { 653 fCompiled->format(results, status); 654 } else { 655 NumberFormatterImpl::formatStatic(fMacros, results, status); 656 } 657 if (U_FAILURE(status)) { 658 return; 659 } 660 results->getStringRef().writeTerminator(status); 661 } 662 663 void LocalizedNumberFormatter::getAffixImpl(bool isPrefix, bool isNegative, UnicodeString& result, 664 UErrorCode& status) const { 665 FormattedStringBuilder string; 666 auto signum = static_cast<Signum>(isNegative ? SIGNUM_NEG : SIGNUM_POS); 667 // Always return affixes for plural form OTHER. 668 static const StandardPlural::Form plural = StandardPlural::OTHER; 669 int32_t prefixLength; 670 if (computeCompiled(status)) { 671 prefixLength = fCompiled->getPrefixSuffix(signum, plural, string, status); 672 } else { 673 prefixLength = NumberFormatterImpl::getPrefixSuffixStatic(fMacros, signum, plural, string, status); 674 } 675 result.remove(); 676 if (isPrefix) { 677 result.append(string.toTempUnicodeString().tempSubStringBetween(0, prefixLength)); 678 } else { 679 result.append(string.toTempUnicodeString().tempSubStringBetween(prefixLength, string.length())); 680 } 681 } 682 683 bool LocalizedNumberFormatter::computeCompiled(UErrorCode& status) const { 684 // fUnsafeCallCount contains memory to be interpreted as an atomic int, most commonly 685 // std::atomic<int32_t>. Since the type of atomic int is platform-dependent, we cast the 686 // bytes in fUnsafeCallCount to u_atomic_int32_t, a typedef for the platform-dependent 687 // atomic int type defined in umutex.h. 688 static_assert( 689 sizeof(u_atomic_int32_t) <= sizeof(fUnsafeCallCount), 690 "Atomic integer size on this platform exceeds the size allocated by fUnsafeCallCount"); 691 auto* callCount = reinterpret_cast<u_atomic_int32_t*>( 692 const_cast<LocalizedNumberFormatter*>(this)->fUnsafeCallCount); 693 694 // A positive value in the atomic int indicates that the data structure is not yet ready; 695 // a negative value indicates that it is ready. If, after the increment, the atomic int 696 // is exactly threshold, then it is the current thread's job to build the data structure. 697 // Note: We set the callCount to INT32_MIN so that if another thread proceeds to increment 698 // the atomic int, the value remains below zero. 699 int32_t currentCount = umtx_loadAcquire(*callCount); 700 if (0 <= currentCount && currentCount <= fMacros.threshold && fMacros.threshold > 0) { 701 currentCount = umtx_atomic_inc(callCount); 702 } 703 704 if (currentCount == fMacros.threshold && fMacros.threshold > 0) { 705 // Build the data structure and then use it (slow to fast path). 706 const NumberFormatterImpl* compiled = new NumberFormatterImpl(fMacros, status); 707 if (compiled == nullptr) { 708 status = U_MEMORY_ALLOCATION_ERROR; 709 return false; 710 } 711 U_ASSERT(fCompiled == nullptr); 712 const_cast<LocalizedNumberFormatter*>(this)->fCompiled = compiled; 713 umtx_storeRelease(*callCount, INT32_MIN); 714 return true; 715 } else if (currentCount < 0) { 716 // The data structure is already built; use it (fast path). 717 U_ASSERT(fCompiled != nullptr); 718 return true; 719 } else { 720 // Format the number without building the data structure (slow path). 721 return false; 722 } 723 } 724 725 const impl::NumberFormatterImpl* LocalizedNumberFormatter::getCompiled() const { 726 return fCompiled; 727 } 728 729 int32_t LocalizedNumberFormatter::getCallCount() const { 730 auto* callCount = reinterpret_cast<u_atomic_int32_t*>( 731 const_cast<LocalizedNumberFormatter*>(this)->fUnsafeCallCount); 732 return umtx_loadAcquire(*callCount); 733 } 734 735 // Note: toFormat defined in number_asformat.cpp 736 737 UnlocalizedNumberFormatter LocalizedNumberFormatter::withoutLocale() const & { 738 MacroProps macros(fMacros); 739 macros.locale = Locale(); 740 return UnlocalizedNumberFormatter(macros); 741 } 742 743 UnlocalizedNumberFormatter LocalizedNumberFormatter::withoutLocale() && { 744 MacroProps macros(std::move(fMacros)); 745 macros.locale = Locale(); 746 return UnlocalizedNumberFormatter(std::move(macros)); 747 } 748 749 const DecimalFormatSymbols* LocalizedNumberFormatter::getDecimalFormatSymbols() const { 750 return fMacros.symbols.getDecimalFormatSymbols(); 751 } 752 753 #if (U_PF_WINDOWS <= U_PLATFORM && U_PLATFORM <= U_PF_CYGWIN) && defined(_MSC_VER) 754 // Warning 4661. 755 #pragma warning(pop) 756 #endif 757 758 #endif /* #if !UCONFIG_NO_FORMATTING */