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(UGroupingStrategy 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(UGroupingStrategy 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 (fMacros
.copyErrorTo(status
)) {
326 return ICU_Utility::makeBogusString();
328 return skeleton::generate(fMacros
, status
);
331 // Declare all classes that implement NumberFormatterSettings
332 // See https://stackoverflow.com/a/495056/1407170
334 class icu::number::NumberFormatterSettings
<icu::number::UnlocalizedNumberFormatter
>;
336 class icu::number::NumberFormatterSettings
<icu::number::LocalizedNumberFormatter
>;
339 UnlocalizedNumberFormatter
NumberFormatter::with() {
340 UnlocalizedNumberFormatter result
;
344 LocalizedNumberFormatter
NumberFormatter::withLocale(const Locale
& locale
) {
345 return with().locale(locale
);
348 UnlocalizedNumberFormatter
349 NumberFormatter::forSkeleton(const UnicodeString
& skeleton
, UErrorCode
& status
) {
350 return skeleton::create(skeleton
, status
);
354 template<typename T
> using NFS
= NumberFormatterSettings
<T
>;
355 using LNF
= LocalizedNumberFormatter
;
356 using UNF
= UnlocalizedNumberFormatter
;
358 UnlocalizedNumberFormatter::UnlocalizedNumberFormatter(const UNF
& other
)
359 : UNF(static_cast<const NFS
<UNF
>&>(other
)) {}
361 UnlocalizedNumberFormatter::UnlocalizedNumberFormatter(const NFS
<UNF
>& other
)
363 // No additional fields to assign
366 UnlocalizedNumberFormatter::UnlocalizedNumberFormatter(UNF
&& src
) U_NOEXCEPT
367 : UNF(static_cast<NFS
<UNF
>&&>(src
)) {}
369 UnlocalizedNumberFormatter::UnlocalizedNumberFormatter(NFS
<UNF
>&& src
) U_NOEXCEPT
370 : NFS
<UNF
>(std::move(src
)) {
371 // No additional fields to assign
374 UnlocalizedNumberFormatter
& UnlocalizedNumberFormatter::operator=(const UNF
& other
) {
375 NFS
<UNF
>::operator=(static_cast<const NFS
<UNF
>&>(other
));
376 // No additional fields to assign
380 UnlocalizedNumberFormatter
& UnlocalizedNumberFormatter::operator=(UNF
&& src
) U_NOEXCEPT
{
381 NFS
<UNF
>::operator=(static_cast<NFS
<UNF
>&&>(src
));
382 // No additional fields to assign
386 LocalizedNumberFormatter::LocalizedNumberFormatter(const LNF
& other
)
387 : LNF(static_cast<const NFS
<LNF
>&>(other
)) {}
389 LocalizedNumberFormatter::LocalizedNumberFormatter(const NFS
<LNF
>& other
)
391 // No additional fields to assign (let call count and compiled formatter reset to defaults)
394 LocalizedNumberFormatter::LocalizedNumberFormatter(LocalizedNumberFormatter
&& src
) U_NOEXCEPT
395 : LNF(static_cast<NFS
<LNF
>&&>(src
)) {}
397 LocalizedNumberFormatter::LocalizedNumberFormatter(NFS
<LNF
>&& src
) U_NOEXCEPT
398 : NFS
<LNF
>(std::move(src
)) {
399 // For the move operators, copy over the compiled formatter.
400 // Note: if the formatter is not compiled, call count information is lost.
401 if (static_cast<LNF
&&>(src
).fCompiled
!= nullptr) {
402 lnfMoveHelper(static_cast<LNF
&&>(src
));
406 LocalizedNumberFormatter
& LocalizedNumberFormatter::operator=(const LNF
& other
) {
407 NFS
<LNF
>::operator=(static_cast<const NFS
<LNF
>&>(other
));
408 // No additional fields to assign (let call count and compiled formatter reset to defaults)
412 LocalizedNumberFormatter
& LocalizedNumberFormatter::operator=(LNF
&& src
) U_NOEXCEPT
{
413 NFS
<LNF
>::operator=(static_cast<NFS
<LNF
>&&>(src
));
414 // For the move operators, copy over the compiled formatter.
415 // Note: if the formatter is not compiled, call count information is lost.
416 if (static_cast<LNF
&&>(src
).fCompiled
!= nullptr) {
417 // Formatter is compiled
418 lnfMoveHelper(static_cast<LNF
&&>(src
));
420 // Reset to default values.
421 auto* callCount
= reinterpret_cast<u_atomic_int32_t
*>(fUnsafeCallCount
);
422 umtx_storeRelease(*callCount
, 0);
428 void LocalizedNumberFormatter::lnfMoveHelper(LNF
&& src
) {
429 // Copy over the compiled formatter and set call count to INT32_MIN as in computeCompiled().
430 // Don't copy the call count directly because doing so requires a loadAcquire/storeRelease.
431 // The bits themselves appear to be platform-dependent, so copying them might not be safe.
432 auto* callCount
= reinterpret_cast<u_atomic_int32_t
*>(fUnsafeCallCount
);
433 umtx_storeRelease(*callCount
, INT32_MIN
);
434 fCompiled
= src
.fCompiled
;
435 // Reset the source object to leave it in a safe state.
436 auto* srcCallCount
= reinterpret_cast<u_atomic_int32_t
*>(src
.fUnsafeCallCount
);
437 umtx_storeRelease(*srcCallCount
, 0);
438 src
.fCompiled
= nullptr;
442 LocalizedNumberFormatter::~LocalizedNumberFormatter() {
446 LocalizedNumberFormatter::LocalizedNumberFormatter(const MacroProps
& macros
, const Locale
& locale
) {
448 fMacros
.locale
= locale
;
451 LocalizedNumberFormatter::LocalizedNumberFormatter(MacroProps
&& macros
, const Locale
& locale
) {
452 fMacros
= std::move(macros
);
453 fMacros
.locale
= locale
;
456 LocalizedNumberFormatter
UnlocalizedNumberFormatter::locale(const Locale
& locale
) const& {
457 return LocalizedNumberFormatter(fMacros
, locale
);
460 LocalizedNumberFormatter
UnlocalizedNumberFormatter::locale(const Locale
& locale
)&& {
461 return LocalizedNumberFormatter(std::move(fMacros
), locale
);
464 SymbolsWrapper::SymbolsWrapper(const SymbolsWrapper
& other
) {
468 SymbolsWrapper::SymbolsWrapper(SymbolsWrapper
&& src
) U_NOEXCEPT
{
469 doMoveFrom(std::move(src
));
472 SymbolsWrapper
& SymbolsWrapper::operator=(const SymbolsWrapper
& other
) {
473 if (this == &other
) {
481 SymbolsWrapper
& SymbolsWrapper::operator=(SymbolsWrapper
&& src
) U_NOEXCEPT
{
486 doMoveFrom(std::move(src
));
490 SymbolsWrapper::~SymbolsWrapper() {
494 void SymbolsWrapper::setTo(const DecimalFormatSymbols
& dfs
) {
497 fPtr
.dfs
= new DecimalFormatSymbols(dfs
);
500 void SymbolsWrapper::setTo(const NumberingSystem
* ns
) {
506 void SymbolsWrapper::doCopyFrom(const SymbolsWrapper
& other
) {
510 // No action necessary
513 // Memory allocation failures are exposed in copyErrorTo()
514 if (other
.fPtr
.dfs
!= nullptr) {
515 fPtr
.dfs
= new DecimalFormatSymbols(*other
.fPtr
.dfs
);
521 // Memory allocation failures are exposed in copyErrorTo()
522 if (other
.fPtr
.ns
!= nullptr) {
523 fPtr
.ns
= new NumberingSystem(*other
.fPtr
.ns
);
531 void SymbolsWrapper::doMoveFrom(SymbolsWrapper
&& src
) {
535 // No action necessary
538 fPtr
.dfs
= src
.fPtr
.dfs
;
539 src
.fPtr
.dfs
= nullptr;
542 fPtr
.ns
= src
.fPtr
.ns
;
543 src
.fPtr
.ns
= nullptr;
548 void SymbolsWrapper::doCleanup() {
551 // No action necessary
562 bool SymbolsWrapper::isDecimalFormatSymbols() const {
563 return fType
== SYMPTR_DFS
;
566 bool SymbolsWrapper::isNumberingSystem() const {
567 return fType
== SYMPTR_NS
;
570 const DecimalFormatSymbols
* SymbolsWrapper::getDecimalFormatSymbols() const {
571 U_ASSERT(fType
== SYMPTR_DFS
);
575 const NumberingSystem
* SymbolsWrapper::getNumberingSystem() const {
576 U_ASSERT(fType
== SYMPTR_NS
);
581 FormattedNumber
LocalizedNumberFormatter::formatInt(int64_t value
, UErrorCode
& status
) const {
582 if (U_FAILURE(status
)) { return FormattedNumber(U_ILLEGAL_ARGUMENT_ERROR
); }
583 auto results
= new UFormattedNumberData();
584 if (results
== nullptr) {
585 status
= U_MEMORY_ALLOCATION_ERROR
;
586 return FormattedNumber(status
);
588 results
->quantity
.setToLong(value
);
589 formatImpl(results
, status
);
591 // Do not save the results object if we encountered a failure.
592 if (U_SUCCESS(status
)) {
593 return FormattedNumber(results
);
596 return FormattedNumber(status
);
600 FormattedNumber
LocalizedNumberFormatter::formatDouble(double value
, UErrorCode
& status
) const {
601 if (U_FAILURE(status
)) { return FormattedNumber(U_ILLEGAL_ARGUMENT_ERROR
); }
602 auto results
= new UFormattedNumberData();
603 if (results
== nullptr) {
604 status
= U_MEMORY_ALLOCATION_ERROR
;
605 return FormattedNumber(status
);
607 results
->quantity
.setToDouble(value
);
608 formatImpl(results
, status
);
610 // Do not save the results object if we encountered a failure.
611 if (U_SUCCESS(status
)) {
612 return FormattedNumber(results
);
615 return FormattedNumber(status
);
619 FormattedNumber
LocalizedNumberFormatter::formatDecimal(StringPiece value
, UErrorCode
& status
) const {
620 if (U_FAILURE(status
)) { return FormattedNumber(U_ILLEGAL_ARGUMENT_ERROR
); }
621 auto results
= new UFormattedNumberData();
622 if (results
== nullptr) {
623 status
= U_MEMORY_ALLOCATION_ERROR
;
624 return FormattedNumber(status
);
626 results
->quantity
.setToDecNumber(value
, status
);
627 formatImpl(results
, status
);
629 // Do not save the results object if we encountered a failure.
630 if (U_SUCCESS(status
)) {
631 return FormattedNumber(results
);
634 return FormattedNumber(status
);
639 LocalizedNumberFormatter::formatDecimalQuantity(const DecimalQuantity
& dq
, UErrorCode
& status
) const {
640 if (U_FAILURE(status
)) { return FormattedNumber(U_ILLEGAL_ARGUMENT_ERROR
); }
641 auto results
= new UFormattedNumberData();
642 if (results
== nullptr) {
643 status
= U_MEMORY_ALLOCATION_ERROR
;
644 return FormattedNumber(status
);
646 results
->quantity
= dq
;
647 formatImpl(results
, status
);
649 // Do not save the results object if we encountered a failure.
650 if (U_SUCCESS(status
)) {
651 return FormattedNumber(results
);
654 return FormattedNumber(status
);
658 void LocalizedNumberFormatter::formatImpl(impl::UFormattedNumberData
* results
, UErrorCode
& status
) const {
659 if (computeCompiled(status
)) {
660 fCompiled
->apply(results
->quantity
, results
->string
, status
);
662 NumberFormatterImpl::applyStatic(fMacros
, results
->quantity
, results
->string
, status
);
666 void LocalizedNumberFormatter::getAffixImpl(bool isPrefix
, bool isNegative
, UnicodeString
& result
,
667 UErrorCode
& status
) const {
668 NumberStringBuilder string
;
669 auto signum
= static_cast<int8_t>(isNegative
? -1 : 1);
670 // Always return affixes for plural form OTHER.
671 static const StandardPlural::Form plural
= StandardPlural::OTHER
;
672 int32_t prefixLength
;
673 if (computeCompiled(status
)) {
674 prefixLength
= fCompiled
->getPrefixSuffix(signum
, plural
, string
, status
);
676 prefixLength
= NumberFormatterImpl::getPrefixSuffixStatic(fMacros
, signum
, plural
, string
, status
);
680 result
.append(string
.toTempUnicodeString().tempSubStringBetween(0, prefixLength
));
682 result
.append(string
.toTempUnicodeString().tempSubStringBetween(prefixLength
, string
.length()));
686 bool LocalizedNumberFormatter::computeCompiled(UErrorCode
& status
) const {
687 // fUnsafeCallCount contains memory to be interpreted as an atomic int, most commonly
688 // std::atomic<int32_t>. Since the type of atomic int is platform-dependent, we cast the
689 // bytes in fUnsafeCallCount to u_atomic_int32_t, a typedef for the platform-dependent
690 // atomic int type defined in umutex.h.
692 sizeof(u_atomic_int32_t
) <= sizeof(fUnsafeCallCount
),
693 "Atomic integer size on this platform exceeds the size allocated by fUnsafeCallCount");
694 auto* callCount
= reinterpret_cast<u_atomic_int32_t
*>(
695 const_cast<LocalizedNumberFormatter
*>(this)->fUnsafeCallCount
);
697 // A positive value in the atomic int indicates that the data structure is not yet ready;
698 // a negative value indicates that it is ready. If, after the increment, the atomic int
699 // is exactly threshold, then it is the current thread's job to build the data structure.
700 // Note: We set the callCount to INT32_MIN so that if another thread proceeds to increment
701 // the atomic int, the value remains below zero.
702 int32_t currentCount
= umtx_loadAcquire(*callCount
);
703 if (0 <= currentCount
&& currentCount
<= fMacros
.threshold
&& fMacros
.threshold
> 0) {
704 currentCount
= umtx_atomic_inc(callCount
);
707 if (currentCount
== fMacros
.threshold
&& fMacros
.threshold
> 0) {
708 // Build the data structure and then use it (slow to fast path).
709 const NumberFormatterImpl
* compiled
= NumberFormatterImpl::fromMacros(fMacros
, status
);
710 U_ASSERT(fCompiled
== nullptr);
711 const_cast<LocalizedNumberFormatter
*>(this)->fCompiled
= compiled
;
712 umtx_storeRelease(*callCount
, INT32_MIN
);
714 } else if (currentCount
< 0) {
715 // The data structure is already built; use it (fast path).
716 U_ASSERT(fCompiled
!= nullptr);
719 // Format the number without building the data structure (slow path).
724 const impl::NumberFormatterImpl
* LocalizedNumberFormatter::getCompiled() const {
728 int32_t LocalizedNumberFormatter::getCallCount() const {
729 auto* callCount
= reinterpret_cast<u_atomic_int32_t
*>(
730 const_cast<LocalizedNumberFormatter
*>(this)->fUnsafeCallCount
);
731 return umtx_loadAcquire(*callCount
);
734 Format
* LocalizedNumberFormatter::toFormat(UErrorCode
& status
) const {
735 LocalPointer
<LocalizedNumberFormatterAsFormat
> retval(
736 new LocalizedNumberFormatterAsFormat(*this, fMacros
.locale
), status
);
737 return retval
.orphan();
741 FormattedNumber::FormattedNumber(FormattedNumber
&& src
) U_NOEXCEPT
742 : fResults(src
.fResults
), fErrorCode(src
.fErrorCode
) {
743 // Disown src.fResults to prevent double-deletion
744 src
.fResults
= nullptr;
745 src
.fErrorCode
= U_INVALID_STATE_ERROR
;
748 FormattedNumber
& FormattedNumber::operator=(FormattedNumber
&& src
) U_NOEXCEPT
{
750 fResults
= src
.fResults
;
751 fErrorCode
= src
.fErrorCode
;
752 // Disown src.fResults to prevent double-deletion
753 src
.fResults
= nullptr;
754 src
.fErrorCode
= U_INVALID_STATE_ERROR
;
758 UnicodeString
FormattedNumber::toString() const {
759 UErrorCode localStatus
= U_ZERO_ERROR
;
760 return toString(localStatus
);
763 UnicodeString
FormattedNumber::toString(UErrorCode
& status
) const {
764 if (U_FAILURE(status
)) {
765 return ICU_Utility::makeBogusString();
767 if (fResults
== nullptr) {
769 return ICU_Utility::makeBogusString();
771 return fResults
->string
.toUnicodeString();
774 Appendable
& FormattedNumber::appendTo(Appendable
& appendable
) {
775 UErrorCode localStatus
= U_ZERO_ERROR
;
776 return appendTo(appendable
, localStatus
);
779 Appendable
& FormattedNumber::appendTo(Appendable
& appendable
, UErrorCode
& status
) {
780 if (U_FAILURE(status
)) {
783 if (fResults
== nullptr) {
787 appendable
.appendString(fResults
->string
.chars(), fResults
->string
.length());
791 void FormattedNumber::populateFieldPosition(FieldPosition
& fieldPosition
, UErrorCode
& status
) {
792 if (U_FAILURE(status
)) {
795 if (fResults
== nullptr) {
799 // in case any users were depending on the old behavior:
800 fieldPosition
.setBeginIndex(0);
801 fieldPosition
.setEndIndex(0);
802 fResults
->string
.nextFieldPosition(fieldPosition
, status
);
805 UBool
FormattedNumber::nextFieldPosition(FieldPosition
& fieldPosition
, UErrorCode
& status
) const {
806 if (U_FAILURE(status
)) {
809 if (fResults
== nullptr) {
813 // NOTE: MSVC sometimes complains when implicitly converting between bool and UBool
814 return fResults
->string
.nextFieldPosition(fieldPosition
, status
) ? TRUE
: FALSE
;
817 void FormattedNumber::populateFieldPositionIterator(FieldPositionIterator
& iterator
, UErrorCode
& status
) {
818 getAllFieldPositions(iterator
, status
);
821 void FormattedNumber::getAllFieldPositions(FieldPositionIterator
& iterator
, UErrorCode
& status
) const {
822 FieldPositionIteratorHandler
fpih(&iterator
, status
);
823 getAllFieldPositionsImpl(fpih
, status
);
826 void FormattedNumber::getAllFieldPositionsImpl(FieldPositionIteratorHandler
& fpih
,
827 UErrorCode
& status
) const {
828 if (U_FAILURE(status
)) {
831 if (fResults
== nullptr) {
835 fResults
->string
.getAllFieldPositions(fpih
, status
);
838 void FormattedNumber::getDecimalQuantity(DecimalQuantity
& output
, UErrorCode
& status
) const {
839 if (U_FAILURE(status
)) {
842 if (fResults
== nullptr) {
846 output
= fResults
->quantity
;
849 FormattedNumber::~FormattedNumber() {
853 #endif /* #if !UCONFIG_NO_FORMATTING */