1 // © 2017 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
4 #include "unicode/utypes.h"
6 #if !UCONFIG_NO_FORMATTING
9 #include "unicode/numberformatter.h"
10 #include "number_decimalquantity.h"
11 #include "number_formatimpl.h"
13 #include "number_asformat.h"
14 #include "number_skeletons.h"
15 #include "number_utils.h"
16 #include "number_utypes.h"
21 using namespace icu::number
;
22 using namespace icu::number::impl
;
24 template<typename Derived
>
25 Derived NumberFormatterSettings
<Derived
>::notation(const Notation
& notation
) const& {
27 // NOTE: Slicing is OK.
28 copy
.fMacros
.notation
= notation
;
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
;
40 template<typename Derived
>
41 Derived NumberFormatterSettings
<Derived
>::unit(const icu::MeasureUnit
& unit
) const& {
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
;
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
;
57 template<typename Derived
>
58 Derived NumberFormatterSettings
<Derived
>::adoptUnit(icu::MeasureUnit
* unit
) const& {
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
);
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
);
83 template<typename Derived
>
84 Derived NumberFormatterSettings
<Derived
>::perUnit(const icu::MeasureUnit
& perUnit
) const& {
86 // See comments above about slicing.
87 copy
.fMacros
.perUnit
= perUnit
;
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
;
99 template<typename Derived
>
100 Derived NumberFormatterSettings
<Derived
>::adoptPerUnit(icu::MeasureUnit
* perUnit
) const& {
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
);
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
);
123 template<typename Derived
>
124 Derived NumberFormatterSettings
<Derived
>::precision(const Precision
& precision
) const& {
126 // NOTE: Slicing is OK.
127 copy
.fMacros
.precision
= precision
;
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
;
139 template<typename Derived
>
140 Derived NumberFormatterSettings
<Derived
>::roundingMode(UNumberFormatRoundingMode roundingMode
) const& {
142 copy
.fMacros
.roundingMode
= roundingMode
;
146 template<typename Derived
>
147 Derived NumberFormatterSettings
<Derived
>::roundingMode(UNumberFormatRoundingMode roundingMode
)&& {
148 Derived
move(std::move(*this));
149 move
.fMacros
.roundingMode
= roundingMode
;
153 template<typename Derived
>
154 Derived NumberFormatterSettings
<Derived
>::grouping(UNumberGroupingStrategy strategy
) const& {
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
);
162 template<typename Derived
>
163 Derived NumberFormatterSettings
<Derived
>::grouping(UNumberGroupingStrategy strategy
)&& {
164 Derived
move(std::move(*this));
165 move
.fMacros
.grouper
= Grouper::forStrategy(strategy
);
169 template<typename Derived
>
170 Derived NumberFormatterSettings
<Derived
>::integerWidth(const IntegerWidth
& style
) const& {
172 copy
.fMacros
.integerWidth
= style
;
176 template<typename Derived
>
177 Derived NumberFormatterSettings
<Derived
>::integerWidth(const IntegerWidth
& style
)&& {
178 Derived
move(std::move(*this));
179 move
.fMacros
.integerWidth
= style
;
183 template<typename Derived
>
184 Derived NumberFormatterSettings
<Derived
>::symbols(const DecimalFormatSymbols
& symbols
) const& {
186 copy
.fMacros
.symbols
.setTo(symbols
);
190 template<typename Derived
>
191 Derived NumberFormatterSettings
<Derived
>::symbols(const DecimalFormatSymbols
& symbols
)&& {
192 Derived
move(std::move(*this));
193 move
.fMacros
.symbols
.setTo(symbols
);
197 template<typename Derived
>
198 Derived NumberFormatterSettings
<Derived
>::adoptSymbols(NumberingSystem
* ns
) const& {
200 copy
.fMacros
.symbols
.setTo(ns
);
204 template<typename Derived
>
205 Derived NumberFormatterSettings
<Derived
>::adoptSymbols(NumberingSystem
* ns
)&& {
206 Derived
move(std::move(*this));
207 move
.fMacros
.symbols
.setTo(ns
);
211 template<typename Derived
>
212 Derived NumberFormatterSettings
<Derived
>::unitWidth(UNumberUnitWidth width
) const& {
214 copy
.fMacros
.unitWidth
= width
;
218 template<typename Derived
>
219 Derived NumberFormatterSettings
<Derived
>::unitWidth(UNumberUnitWidth width
)&& {
220 Derived
move(std::move(*this));
221 move
.fMacros
.unitWidth
= width
;
225 template<typename Derived
>
226 Derived NumberFormatterSettings
<Derived
>::sign(UNumberSignDisplay style
) const& {
228 copy
.fMacros
.sign
= style
;
232 template<typename Derived
>
233 Derived NumberFormatterSettings
<Derived
>::sign(UNumberSignDisplay style
)&& {
234 Derived
move(std::move(*this));
235 move
.fMacros
.sign
= style
;
239 template<typename Derived
>
240 Derived NumberFormatterSettings
<Derived
>::decimal(UNumberDecimalSeparatorDisplay style
) const& {
242 copy
.fMacros
.decimal
= style
;
246 template<typename Derived
>
247 Derived NumberFormatterSettings
<Derived
>::decimal(UNumberDecimalSeparatorDisplay style
)&& {
248 Derived
move(std::move(*this));
249 move
.fMacros
.decimal
= style
;
253 template<typename Derived
>
254 Derived NumberFormatterSettings
<Derived
>::scale(const Scale
& scale
) const& {
256 copy
.fMacros
.scale
= scale
;
260 template<typename Derived
>
261 Derived NumberFormatterSettings
<Derived
>::scale(const Scale
& scale
)&& {
262 Derived
move(std::move(*this));
263 move
.fMacros
.scale
= scale
;
267 template<typename Derived
>
268 Derived NumberFormatterSettings
<Derived
>::padding(const Padder
& padder
) const& {
270 copy
.fMacros
.padder
= padder
;
274 template<typename Derived
>
275 Derived NumberFormatterSettings
<Derived
>::padding(const Padder
& padder
)&& {
276 Derived
move(std::move(*this));
277 move
.fMacros
.padder
= padder
;
281 template<typename Derived
>
282 Derived NumberFormatterSettings
<Derived
>::threshold(int32_t threshold
) const& {
284 copy
.fMacros
.threshold
= threshold
;
288 template<typename Derived
>
289 Derived NumberFormatterSettings
<Derived
>::threshold(int32_t threshold
)&& {
290 Derived
move(std::move(*this));
291 move
.fMacros
.threshold
= threshold
;
295 template<typename Derived
>
296 Derived NumberFormatterSettings
<Derived
>::macros(const impl::MacroProps
& macros
) const& {
298 copy
.fMacros
= macros
;
302 template<typename Derived
>
303 Derived NumberFormatterSettings
<Derived
>::macros(const impl::MacroProps
& macros
)&& {
304 Derived
move(std::move(*this));
305 move
.fMacros
= macros
;
309 template<typename Derived
>
310 Derived NumberFormatterSettings
<Derived
>::macros(impl::MacroProps
&& macros
) const& {
312 copy
.fMacros
= std::move(macros
);
316 template<typename Derived
>
317 Derived NumberFormatterSettings
<Derived
>::macros(impl::MacroProps
&& macros
)&& {
318 Derived
move(std::move(*this));
319 move
.fMacros
= std::move(macros
);
323 template<typename Derived
>
324 UnicodeString NumberFormatterSettings
<Derived
>::toSkeleton(UErrorCode
& status
) const {
325 if (U_FAILURE(status
)) {
326 return ICU_Utility::makeBogusString();
328 if (fMacros
.copyErrorTo(status
)) {
329 return ICU_Utility::makeBogusString();
331 return skeleton::generate(fMacros
, status
);
334 template<typename Derived
>
335 LocalPointer
<Derived
> NumberFormatterSettings
<Derived
>::clone() const & {
336 return LocalPointer
<Derived
>(new Derived(*this));
339 template<typename Derived
>
340 LocalPointer
<Derived
> NumberFormatterSettings
<Derived
>::clone() && {
341 return LocalPointer
<Derived
>(new Derived(std::move(*this)));
344 // Declare all classes that implement NumberFormatterSettings
345 // See https://stackoverflow.com/a/495056/1407170
347 class icu::number::NumberFormatterSettings
<icu::number::UnlocalizedNumberFormatter
>;
349 class icu::number::NumberFormatterSettings
<icu::number::LocalizedNumberFormatter
>;
352 UnlocalizedNumberFormatter
NumberFormatter::with() {
353 UnlocalizedNumberFormatter result
;
357 LocalizedNumberFormatter
NumberFormatter::withLocale(const Locale
& locale
) {
358 return with().locale(locale
);
361 UnlocalizedNumberFormatter
362 NumberFormatter::forSkeleton(const UnicodeString
& skeleton
, UErrorCode
& status
) {
363 return skeleton::create(skeleton
, nullptr, status
);
366 UnlocalizedNumberFormatter
367 NumberFormatter::forSkeleton(const UnicodeString
& skeleton
, UParseError
& perror
, UErrorCode
& status
) {
368 return skeleton::create(skeleton
, &perror
, status
);
372 template<typename T
> using NFS
= NumberFormatterSettings
<T
>;
373 using LNF
= LocalizedNumberFormatter
;
374 using UNF
= UnlocalizedNumberFormatter
;
376 UnlocalizedNumberFormatter::UnlocalizedNumberFormatter(const UNF
& other
)
377 : UNF(static_cast<const NFS
<UNF
>&>(other
)) {}
379 UnlocalizedNumberFormatter::UnlocalizedNumberFormatter(const NFS
<UNF
>& other
)
381 // No additional fields to assign
384 // Make default copy constructor call the NumberFormatterSettings copy constructor.
385 UnlocalizedNumberFormatter::UnlocalizedNumberFormatter(UNF
&& src
) U_NOEXCEPT
386 : UNF(static_cast<NFS
<UNF
>&&>(src
)) {}
388 UnlocalizedNumberFormatter::UnlocalizedNumberFormatter(NFS
<UNF
>&& src
) U_NOEXCEPT
389 : NFS
<UNF
>(std::move(src
)) {
390 // No additional fields to assign
393 UnlocalizedNumberFormatter
& UnlocalizedNumberFormatter::operator=(const UNF
& other
) {
394 NFS
<UNF
>::operator=(static_cast<const NFS
<UNF
>&>(other
));
395 // No additional fields to assign
399 UnlocalizedNumberFormatter
& UnlocalizedNumberFormatter::operator=(UNF
&& src
) U_NOEXCEPT
{
400 NFS
<UNF
>::operator=(static_cast<NFS
<UNF
>&&>(src
));
401 // No additional fields to assign
405 // Make default copy constructor call the NumberFormatterSettings copy constructor.
406 LocalizedNumberFormatter::LocalizedNumberFormatter(const LNF
& other
)
407 : LNF(static_cast<const NFS
<LNF
>&>(other
)) {}
409 LocalizedNumberFormatter::LocalizedNumberFormatter(const NFS
<LNF
>& other
)
411 // No additional fields to assign (let call count and compiled formatter reset to defaults)
414 LocalizedNumberFormatter::LocalizedNumberFormatter(LocalizedNumberFormatter
&& src
) U_NOEXCEPT
415 : LNF(static_cast<NFS
<LNF
>&&>(src
)) {}
417 LocalizedNumberFormatter::LocalizedNumberFormatter(NFS
<LNF
>&& src
) U_NOEXCEPT
418 : NFS
<LNF
>(std::move(src
)) {
419 // For the move operators, copy over the compiled formatter.
420 // Note: if the formatter is not compiled, call count information is lost.
421 if (static_cast<LNF
&&>(src
).fCompiled
!= nullptr) {
422 lnfMoveHelper(static_cast<LNF
&&>(src
));
426 LocalizedNumberFormatter
& LocalizedNumberFormatter::operator=(const LNF
& other
) {
427 NFS
<LNF
>::operator=(static_cast<const NFS
<LNF
>&>(other
));
428 // Reset to default values.
433 LocalizedNumberFormatter
& LocalizedNumberFormatter::operator=(LNF
&& src
) U_NOEXCEPT
{
434 NFS
<LNF
>::operator=(static_cast<NFS
<LNF
>&&>(src
));
435 // For the move operators, copy over the compiled formatter.
436 // Note: if the formatter is not compiled, call count information is lost.
437 if (static_cast<LNF
&&>(src
).fCompiled
!= nullptr) {
438 // Formatter is compiled
439 lnfMoveHelper(static_cast<LNF
&&>(src
));
446 void LocalizedNumberFormatter::clear() {
447 // Reset to default values.
448 auto* callCount
= reinterpret_cast<u_atomic_int32_t
*>(fUnsafeCallCount
);
449 umtx_storeRelease(*callCount
, 0);
454 void LocalizedNumberFormatter::lnfMoveHelper(LNF
&& src
) {
455 // Copy over the compiled formatter and set call count to INT32_MIN as in computeCompiled().
456 // Don't copy the call count directly because doing so requires a loadAcquire/storeRelease.
457 // The bits themselves appear to be platform-dependent, so copying them might not be safe.
458 auto* callCount
= reinterpret_cast<u_atomic_int32_t
*>(fUnsafeCallCount
);
459 umtx_storeRelease(*callCount
, INT32_MIN
);
461 fCompiled
= src
.fCompiled
;
462 // Reset the source object to leave it in a safe state.
463 auto* srcCallCount
= reinterpret_cast<u_atomic_int32_t
*>(src
.fUnsafeCallCount
);
464 umtx_storeRelease(*srcCallCount
, 0);
465 src
.fCompiled
= nullptr;
469 LocalizedNumberFormatter::~LocalizedNumberFormatter() {
473 LocalizedNumberFormatter::LocalizedNumberFormatter(const MacroProps
& macros
, const Locale
& locale
) {
475 fMacros
.locale
= locale
;
478 LocalizedNumberFormatter::LocalizedNumberFormatter(MacroProps
&& macros
, const Locale
& locale
) {
479 fMacros
= std::move(macros
);
480 fMacros
.locale
= locale
;
483 LocalizedNumberFormatter
UnlocalizedNumberFormatter::locale(const Locale
& locale
) const& {
484 return LocalizedNumberFormatter(fMacros
, locale
);
487 LocalizedNumberFormatter
UnlocalizedNumberFormatter::locale(const Locale
& locale
)&& {
488 return LocalizedNumberFormatter(std::move(fMacros
), locale
);
491 SymbolsWrapper::SymbolsWrapper(const SymbolsWrapper
& other
) {
495 SymbolsWrapper::SymbolsWrapper(SymbolsWrapper
&& src
) U_NOEXCEPT
{
496 doMoveFrom(std::move(src
));
499 SymbolsWrapper
& SymbolsWrapper::operator=(const SymbolsWrapper
& other
) {
500 if (this == &other
) {
508 SymbolsWrapper
& SymbolsWrapper::operator=(SymbolsWrapper
&& src
) U_NOEXCEPT
{
513 doMoveFrom(std::move(src
));
517 SymbolsWrapper::~SymbolsWrapper() {
521 // Apple <rdar://problem/49955427>
522 void SymbolsWrapper::setDFSShallowCopy(UBool shallow
) {
524 if (fType
== SYMPTR_DFS
) {
525 fType
= SYMPTR_DFS_SHALLOWCOPY
;
527 } else if (fType
== SYMPTR_DFS_SHALLOWCOPY
) {
532 void SymbolsWrapper::setTo(const DecimalFormatSymbols
& dfs
) {
535 fPtr
.dfs
= new DecimalFormatSymbols(dfs
);
538 void SymbolsWrapper::setTo(const NumberingSystem
* ns
) {
544 void SymbolsWrapper::doCopyFrom(const SymbolsWrapper
& other
) {
548 // No action necessary
551 // Memory allocation failures are exposed in copyErrorTo()
552 if (other
.fPtr
.dfs
!= nullptr) {
553 fPtr
.dfs
= new DecimalFormatSymbols(*other
.fPtr
.dfs
);
558 case SYMPTR_DFS_SHALLOWCOPY
: // Apple <rdar://problem/49955427>
559 // DecimalFormatSymbols pointer copy, do not clone
560 fPtr
.dfs
= other
.fPtr
.dfs
;
563 // Memory allocation failures are exposed in copyErrorTo()
564 if (other
.fPtr
.ns
!= nullptr) {
565 fPtr
.ns
= new NumberingSystem(*other
.fPtr
.ns
);
573 void SymbolsWrapper::doMoveFrom(SymbolsWrapper
&& src
) {
577 // No action necessary
580 case SYMPTR_DFS_SHALLOWCOPY
:
581 fPtr
.dfs
= src
.fPtr
.dfs
;
582 src
.fPtr
.dfs
= nullptr;
585 fPtr
.ns
= src
.fPtr
.ns
;
586 src
.fPtr
.ns
= nullptr;
591 void SymbolsWrapper::doCleanup() {
594 // No action necessary
599 case SYMPTR_DFS_SHALLOWCOPY
: // Apple <rdar://problem/49955427>
600 // No action necessary
608 bool SymbolsWrapper::isDecimalFormatSymbols() const {
609 return (fType
== SYMPTR_DFS
|| fType
== SYMPTR_DFS_SHALLOWCOPY
);
612 bool SymbolsWrapper::isNumberingSystem() const {
613 return fType
== SYMPTR_NS
;
616 const DecimalFormatSymbols
* SymbolsWrapper::getDecimalFormatSymbols() const {
617 U_ASSERT(fType
== SYMPTR_DFS
|| fType
== SYMPTR_DFS_SHALLOWCOPY
);
621 const NumberingSystem
* SymbolsWrapper::getNumberingSystem() const {
622 U_ASSERT(fType
== SYMPTR_NS
);
627 FormattedNumber
LocalizedNumberFormatter::formatInt(int64_t value
, UErrorCode
& status
) const {
628 if (U_FAILURE(status
)) { return FormattedNumber(U_ILLEGAL_ARGUMENT_ERROR
); }
629 auto results
= new UFormattedNumberData();
630 if (results
== nullptr) {
631 status
= U_MEMORY_ALLOCATION_ERROR
;
632 return FormattedNumber(status
);
634 results
->quantity
.setToLong(value
);
635 formatImpl(results
, status
);
637 // Do not save the results object if we encountered a failure.
638 if (U_SUCCESS(status
)) {
639 return FormattedNumber(results
);
642 return FormattedNumber(status
);
646 FormattedNumber
LocalizedNumberFormatter::formatDouble(double value
, UErrorCode
& status
) const {
647 if (U_FAILURE(status
)) { return FormattedNumber(U_ILLEGAL_ARGUMENT_ERROR
); }
648 auto results
= new UFormattedNumberData();
649 if (results
== nullptr) {
650 status
= U_MEMORY_ALLOCATION_ERROR
;
651 return FormattedNumber(status
);
653 results
->quantity
.setToDouble(value
);
654 if (fMacros
.adjustDoublePrecision
) { // Apple addition for <rdar://problem/39240173>
655 UErrorCode localStatus
= U_ZERO_ERROR
;
656 int32_t magnitude
= results
->quantity
.getMagnitude();
657 results
->quantity
.roundToMagnitude(magnitude
-14, kDefaultMode
, localStatus
);
659 formatImpl(results
, status
);
661 // Do not save the results object if we encountered a failure.
662 if (U_SUCCESS(status
)) {
663 return FormattedNumber(results
);
666 return FormattedNumber(status
);
670 FormattedNumber
LocalizedNumberFormatter::formatDecimal(StringPiece value
, UErrorCode
& status
) const {
671 if (U_FAILURE(status
)) { return FormattedNumber(U_ILLEGAL_ARGUMENT_ERROR
); }
672 auto results
= new UFormattedNumberData();
673 if (results
== nullptr) {
674 status
= U_MEMORY_ALLOCATION_ERROR
;
675 return FormattedNumber(status
);
677 results
->quantity
.setToDecNumber(value
, status
);
678 formatImpl(results
, status
);
680 // Do not save the results object if we encountered a failure.
681 if (U_SUCCESS(status
)) {
682 return FormattedNumber(results
);
685 return FormattedNumber(status
);
690 LocalizedNumberFormatter::formatDecimalQuantity(const DecimalQuantity
& dq
, UErrorCode
& status
) const {
691 if (U_FAILURE(status
)) { return FormattedNumber(U_ILLEGAL_ARGUMENT_ERROR
); }
692 auto results
= new UFormattedNumberData();
693 if (results
== nullptr) {
694 status
= U_MEMORY_ALLOCATION_ERROR
;
695 return FormattedNumber(status
);
697 results
->quantity
= dq
;
698 formatImpl(results
, status
);
700 // Do not save the results object if we encountered a failure.
701 if (U_SUCCESS(status
)) {
702 return FormattedNumber(results
);
705 return FormattedNumber(status
);
709 void LocalizedNumberFormatter::formatImpl(impl::UFormattedNumberData
* results
, UErrorCode
& status
) const {
710 if (computeCompiled(status
)) {
711 fCompiled
->format(results
->quantity
, results
->getStringRef(), status
);
713 NumberFormatterImpl::formatStatic(fMacros
, results
->quantity
, results
->getStringRef(), status
);
715 if (U_FAILURE(status
)) {
718 results
->getStringRef().writeTerminator(status
);
721 void LocalizedNumberFormatter::getAffixImpl(bool isPrefix
, bool isNegative
, UnicodeString
& result
,
722 UErrorCode
& status
) const {
723 NumberStringBuilder string
;
724 auto signum
= static_cast<int8_t>(isNegative
? -1 : 1);
725 // Always return affixes for plural form OTHER.
726 static const StandardPlural::Form plural
= StandardPlural::OTHER
;
727 int32_t prefixLength
;
728 if (computeCompiled(status
)) {
729 prefixLength
= fCompiled
->getPrefixSuffix(signum
, plural
, string
, status
);
731 prefixLength
= NumberFormatterImpl::getPrefixSuffixStatic(fMacros
, signum
, plural
, string
, status
);
735 result
.append(string
.toTempUnicodeString().tempSubStringBetween(0, prefixLength
));
737 result
.append(string
.toTempUnicodeString().tempSubStringBetween(prefixLength
, string
.length()));
741 bool LocalizedNumberFormatter::computeCompiled(UErrorCode
& status
) const {
742 // fUnsafeCallCount contains memory to be interpreted as an atomic int, most commonly
743 // std::atomic<int32_t>. Since the type of atomic int is platform-dependent, we cast the
744 // bytes in fUnsafeCallCount to u_atomic_int32_t, a typedef for the platform-dependent
745 // atomic int type defined in umutex.h.
747 sizeof(u_atomic_int32_t
) <= sizeof(fUnsafeCallCount
),
748 "Atomic integer size on this platform exceeds the size allocated by fUnsafeCallCount");
749 auto* callCount
= reinterpret_cast<u_atomic_int32_t
*>(
750 const_cast<LocalizedNumberFormatter
*>(this)->fUnsafeCallCount
);
752 // A positive value in the atomic int indicates that the data structure is not yet ready;
753 // a negative value indicates that it is ready. If, after the increment, the atomic int
754 // is exactly threshold, then it is the current thread's job to build the data structure.
755 // Note: We set the callCount to INT32_MIN so that if another thread proceeds to increment
756 // the atomic int, the value remains below zero.
757 int32_t currentCount
= umtx_loadAcquire(*callCount
);
758 if (0 <= currentCount
&& currentCount
<= fMacros
.threshold
&& fMacros
.threshold
> 0) {
759 currentCount
= umtx_atomic_inc(callCount
);
762 if (currentCount
== fMacros
.threshold
&& fMacros
.threshold
> 0) {
763 // Build the data structure and then use it (slow to fast path).
764 const NumberFormatterImpl
* compiled
= new NumberFormatterImpl(fMacros
, status
);
765 if (compiled
== nullptr) {
766 status
= U_MEMORY_ALLOCATION_ERROR
;
769 U_ASSERT(fCompiled
== nullptr);
770 const_cast<LocalizedNumberFormatter
*>(this)->fCompiled
= compiled
;
771 umtx_storeRelease(*callCount
, INT32_MIN
);
773 } else if (currentCount
< 0) {
774 // The data structure is already built; use it (fast path).
775 U_ASSERT(fCompiled
!= nullptr);
778 // Format the number without building the data structure (slow path).
783 const impl::NumberFormatterImpl
* LocalizedNumberFormatter::getCompiled() const {
787 int32_t LocalizedNumberFormatter::getCallCount() const {
788 auto* callCount
= reinterpret_cast<u_atomic_int32_t
*>(
789 const_cast<LocalizedNumberFormatter
*>(this)->fUnsafeCallCount
);
790 return umtx_loadAcquire(*callCount
);
793 Format
* LocalizedNumberFormatter::toFormat(UErrorCode
& status
) const {
794 if (U_FAILURE(status
)) {
797 LocalPointer
<LocalizedNumberFormatterAsFormat
> retval(
798 new LocalizedNumberFormatterAsFormat(*this, fMacros
.locale
), status
);
799 return retval
.orphan();
802 // Apple <rdar://problem/49955427>
803 void LocalizedNumberFormatter::setDFSShallowCopy(UBool shallow
) {
804 fMacros
.symbols
.setDFSShallowCopy(shallow
);
807 #endif /* #if !UCONFIG_NO_FORMATTING */