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>
notation(const Notation & notation) const35 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>
notation(const Notation & notation)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>
unit(const icu::MeasureUnit & unit) const51 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>
unit(const icu::MeasureUnit & unit)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>
adoptUnit(icu::MeasureUnit * unit) const68 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>
adoptUnit(icu::MeasureUnit * unit)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>
perUnit(const icu::MeasureUnit & perUnit) const94 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>
perUnit(const icu::MeasureUnit & perUnit)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>
adoptPerUnit(icu::MeasureUnit * perUnit) const110 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>
adoptPerUnit(icu::MeasureUnit * perUnit)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>
precision(const Precision & precision) const134 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>
precision(const Precision & precision)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>
roundingMode(UNumberFormatRoundingMode roundingMode) const150 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>
roundingMode(UNumberFormatRoundingMode roundingMode)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>
grouping(UNumberGroupingStrategy strategy) const164 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>
grouping(UNumberGroupingStrategy strategy)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>
integerWidth(const IntegerWidth & style) const180 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>
integerWidth(const IntegerWidth & style)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>
symbols(const DecimalFormatSymbols & symbols) const194 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>
symbols(const DecimalFormatSymbols & symbols)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>
adoptSymbols(NumberingSystem * ns) const208 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>
adoptSymbols(NumberingSystem * ns)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>
unitWidth(UNumberUnitWidth width) const222 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>
unitWidth(UNumberUnitWidth width)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>
sign(UNumberSignDisplay style) const236 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>
sign(UNumberSignDisplay style)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>
decimal(UNumberDecimalSeparatorDisplay style) const250 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>
decimal(UNumberDecimalSeparatorDisplay style)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>
scale(const Scale & scale) const264 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>
scale(const Scale & scale)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>
usage(const StringPiece usage) const278 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>
usage(const StringPiece usage)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>
padding(const Padder & padder) const292 Derived NumberFormatterSettings<Derived>::padding(const Padder& padder) const& {
293     Derived copy(*this);
294     copy.fMacros.padder = padder;
295     return copy;
296 }
297 
298 template<typename Derived>
padding(const Padder & padder)299 Derived NumberFormatterSettings<Derived>::padding(const Padder& padder)&& {
300     Derived move(std::move(*this));
301     move.fMacros.padder = padder;
302     return move;
303 }
304 
305 template<typename Derived>
threshold(int32_t threshold) const306 Derived NumberFormatterSettings<Derived>::threshold(int32_t threshold) const& {
307     Derived copy(*this);
308     copy.fMacros.threshold = threshold;
309     return copy;
310 }
311 
312 template<typename Derived>
threshold(int32_t threshold)313 Derived NumberFormatterSettings<Derived>::threshold(int32_t threshold)&& {
314     Derived move(std::move(*this));
315     move.fMacros.threshold = threshold;
316     return move;
317 }
318 
319 template<typename Derived>
macros(const impl::MacroProps & macros) const320 Derived NumberFormatterSettings<Derived>::macros(const impl::MacroProps& macros) const& {
321     Derived copy(*this);
322     copy.fMacros = macros;
323     return copy;
324 }
325 
326 template<typename Derived>
macros(const impl::MacroProps & macros)327 Derived NumberFormatterSettings<Derived>::macros(const impl::MacroProps& macros)&& {
328     Derived move(std::move(*this));
329     move.fMacros = macros;
330     return move;
331 }
332 
333 template<typename Derived>
macros(impl::MacroProps && macros) const334 Derived NumberFormatterSettings<Derived>::macros(impl::MacroProps&& macros) const& {
335     Derived copy(*this);
336     copy.fMacros = std::move(macros);
337     return copy;
338 }
339 
340 template<typename Derived>
macros(impl::MacroProps && macros)341 Derived NumberFormatterSettings<Derived>::macros(impl::MacroProps&& macros)&& {
342     Derived move(std::move(*this));
343     move.fMacros = std::move(macros);
344     return move;
345 }
346 
347 // Note: toSkeleton defined in number_skeletons.cpp
348 
349 template<typename Derived>
clone() const350 LocalPointer<Derived> NumberFormatterSettings<Derived>::clone() const & {
351     return LocalPointer<Derived>(new Derived(*this));
352 }
353 
354 template<typename Derived>
clone()355 LocalPointer<Derived> NumberFormatterSettings<Derived>::clone() && {
356     return LocalPointer<Derived>(new Derived(std::move(*this)));
357 }
358 
359 // Declare all classes that implement NumberFormatterSettings
360 // See https://stackoverflow.com/a/495056/1407170
361 template
362 class icu::number::NumberFormatterSettings<icu::number::UnlocalizedNumberFormatter>;
363 template
364 class icu::number::NumberFormatterSettings<icu::number::LocalizedNumberFormatter>;
365 
366 
with()367 UnlocalizedNumberFormatter NumberFormatter::with() {
368     UnlocalizedNumberFormatter result;
369     return result;
370 }
371 
withLocale(const Locale & locale)372 LocalizedNumberFormatter NumberFormatter::withLocale(const Locale& locale) {
373     return with().locale(locale);
374 }
375 
376 // Note: forSkeleton defined in number_skeletons.cpp
377 
378 
379 template<typename T> using NFS = NumberFormatterSettings<T>;
380 using LNF = LocalizedNumberFormatter;
381 using UNF = UnlocalizedNumberFormatter;
382 
UnlocalizedNumberFormatter(const UNF & other)383 UnlocalizedNumberFormatter::UnlocalizedNumberFormatter(const UNF& other)
384         : UNF(static_cast<const NFS<UNF>&>(other)) {}
385 
UnlocalizedNumberFormatter(const NFS<UNF> & other)386 UnlocalizedNumberFormatter::UnlocalizedNumberFormatter(const NFS<UNF>& other)
387         : NFS<UNF>(other) {
388     // No additional fields to assign
389 }
390 
391 // Make default copy constructor call the NumberFormatterSettings copy constructor.
UnlocalizedNumberFormatter(UNF && src)392 UnlocalizedNumberFormatter::UnlocalizedNumberFormatter(UNF&& src) U_NOEXCEPT
393         : UNF(static_cast<NFS<UNF>&&>(src)) {}
394 
UnlocalizedNumberFormatter(NFS<UNF> && src)395 UnlocalizedNumberFormatter::UnlocalizedNumberFormatter(NFS<UNF>&& src) U_NOEXCEPT
396         : NFS<UNF>(std::move(src)) {
397     // No additional fields to assign
398 }
399 
operator =(const UNF & other)400 UnlocalizedNumberFormatter& UnlocalizedNumberFormatter::operator=(const UNF& other) {
401     NFS<UNF>::operator=(static_cast<const NFS<UNF>&>(other));
402     // No additional fields to assign
403     return *this;
404 }
405 
operator =(UNF && src)406 UnlocalizedNumberFormatter& UnlocalizedNumberFormatter::operator=(UNF&& src) U_NOEXCEPT {
407     NFS<UNF>::operator=(static_cast<NFS<UNF>&&>(src));
408     // No additional fields to assign
409     return *this;
410 }
411 
412 // Make default copy constructor call the NumberFormatterSettings copy constructor.
LocalizedNumberFormatter(const LNF & other)413 LocalizedNumberFormatter::LocalizedNumberFormatter(const LNF& other)
414         : LNF(static_cast<const NFS<LNF>&>(other)) {}
415 
LocalizedNumberFormatter(const NFS<LNF> & other)416 LocalizedNumberFormatter::LocalizedNumberFormatter(const NFS<LNF>& other)
417         : NFS<LNF>(other) {
418     UErrorCode localStatus = U_ZERO_ERROR; // Can't bubble up the error
419     lnfCopyHelper(static_cast<const LNF&>(other), localStatus);
420 }
421 
LocalizedNumberFormatter(LocalizedNumberFormatter && src)422 LocalizedNumberFormatter::LocalizedNumberFormatter(LocalizedNumberFormatter&& src) U_NOEXCEPT
423         : LNF(static_cast<NFS<LNF>&&>(src)) {}
424 
LocalizedNumberFormatter(NFS<LNF> && src)425 LocalizedNumberFormatter::LocalizedNumberFormatter(NFS<LNF>&& src) U_NOEXCEPT
426         : NFS<LNF>(std::move(src)) {
427     lnfMoveHelper(std::move(static_cast<LNF&&>(src)));
428 }
429 
operator =(const LNF & other)430 LocalizedNumberFormatter& LocalizedNumberFormatter::operator=(const LNF& other) {
431     if (this == &other) { return *this; }  // self-assignment: no-op
432     NFS<LNF>::operator=(static_cast<const NFS<LNF>&>(other));
433     UErrorCode localStatus = U_ZERO_ERROR; // Can't bubble up the error
434     lnfCopyHelper(other, localStatus);
435     return *this;
436 }
437 
operator =(LNF && src)438 LocalizedNumberFormatter& LocalizedNumberFormatter::operator=(LNF&& src) U_NOEXCEPT {
439     NFS<LNF>::operator=(static_cast<NFS<LNF>&&>(src));
440     lnfMoveHelper(std::move(src));
441     return *this;
442 }
443 
resetCompiled()444 void LocalizedNumberFormatter::resetCompiled() {
445     auto* callCount = reinterpret_cast<u_atomic_int32_t*>(fUnsafeCallCount);
446     umtx_storeRelease(*callCount, 0);
447     fCompiled = nullptr;
448 }
449 
lnfMoveHelper(LNF && src)450 void LocalizedNumberFormatter::lnfMoveHelper(LNF&& src) {
451     // Copy over the compiled formatter and set call count to INT32_MIN as in computeCompiled().
452     // Don't copy the call count directly because doing so requires a loadAcquire/storeRelease.
453     // The bits themselves appear to be platform-dependent, so copying them might not be safe.
454     delete fCompiled;
455     if (src.fCompiled != nullptr) {
456         auto* callCount = reinterpret_cast<u_atomic_int32_t*>(fUnsafeCallCount);
457         umtx_storeRelease(*callCount, INT32_MIN);
458         fCompiled = src.fCompiled;
459         // Reset the source object to leave it in a safe state.
460         src.resetCompiled();
461     } else {
462         resetCompiled();
463     }
464 
465     // Unconditionally move the warehouse
466     delete fWarehouse;
467     fWarehouse = src.fWarehouse;
468     src.fWarehouse = nullptr;
469 }
470 
lnfCopyHelper(const LNF &,UErrorCode & status)471 void LocalizedNumberFormatter::lnfCopyHelper(const LNF&, UErrorCode& status) {
472     // When copying, always reset the compiled formatter.
473     delete fCompiled;
474     resetCompiled();
475 
476     // If MacroProps has a reference to AffixPatternProvider, we need to copy it.
477     // If MacroProps has a reference to PluralRules, copy that one, too.
478     delete fWarehouse;
479     if (fMacros.affixProvider || fMacros.rules) {
480         LocalPointer<DecimalFormatWarehouse> warehouse(new DecimalFormatWarehouse(), status);
481         if (U_FAILURE(status)) {
482             fWarehouse = nullptr;
483             return;
484         }
485         if (fMacros.affixProvider) {
486             warehouse->affixProvider.setTo(fMacros.affixProvider, status);
487             fMacros.affixProvider = &warehouse->affixProvider.get();
488         }
489         if (fMacros.rules) {
490             warehouse->rules.adoptInsteadAndCheckErrorCode(
491                 new PluralRules(*fMacros.rules), status);
492             fMacros.rules = warehouse->rules.getAlias();
493         }
494         fWarehouse = warehouse.orphan();
495     } else {
496         fWarehouse = nullptr;
497     }
498 }
499 
500 
~LocalizedNumberFormatter()501 LocalizedNumberFormatter::~LocalizedNumberFormatter() {
502     delete fCompiled;
503     delete fWarehouse;
504 }
505 
LocalizedNumberFormatter(const MacroProps & macros,const Locale & locale)506 LocalizedNumberFormatter::LocalizedNumberFormatter(const MacroProps& macros, const Locale& locale) {
507     fMacros = macros;
508     fMacros.locale = locale;
509 }
510 
LocalizedNumberFormatter(MacroProps && macros,const Locale & locale)511 LocalizedNumberFormatter::LocalizedNumberFormatter(MacroProps&& macros, const Locale& locale) {
512     fMacros = std::move(macros);
513     fMacros.locale = locale;
514 }
515 
locale(const Locale & locale) const516 LocalizedNumberFormatter UnlocalizedNumberFormatter::locale(const Locale& locale) const& {
517     return LocalizedNumberFormatter(fMacros, locale);
518 }
519 
locale(const Locale & locale)520 LocalizedNumberFormatter UnlocalizedNumberFormatter::locale(const Locale& locale)&& {
521     return LocalizedNumberFormatter(std::move(fMacros), locale);
522 }
523 
formatInt(int64_t value,UErrorCode & status) const524 FormattedNumber LocalizedNumberFormatter::formatInt(int64_t value, UErrorCode& status) const {
525     if (U_FAILURE(status)) { return FormattedNumber(U_ILLEGAL_ARGUMENT_ERROR); }
526     auto results = new UFormattedNumberData();
527     if (results == nullptr) {
528         status = U_MEMORY_ALLOCATION_ERROR;
529         return FormattedNumber(status);
530     }
531     results->quantity.setToLong(value);
532     formatImpl(results, status);
533 
534     // Do not save the results object if we encountered a failure.
535     if (U_SUCCESS(status)) {
536         return FormattedNumber(results);
537     } else {
538         delete results;
539         return FormattedNumber(status);
540     }
541 }
542 
formatDouble(double value,UErrorCode & status) const543 FormattedNumber LocalizedNumberFormatter::formatDouble(double value, UErrorCode& status) const {
544     if (U_FAILURE(status)) { return FormattedNumber(U_ILLEGAL_ARGUMENT_ERROR); }
545     auto results = new UFormattedNumberData();
546     if (results == nullptr) {
547         status = U_MEMORY_ALLOCATION_ERROR;
548         return FormattedNumber(status);
549     }
550     results->quantity.setToDouble(value);
551     formatImpl(results, status);
552 
553     // Do not save the results object if we encountered a failure.
554     if (U_SUCCESS(status)) {
555         return FormattedNumber(results);
556     } else {
557         delete results;
558         return FormattedNumber(status);
559     }
560 }
561 
formatDecimal(StringPiece value,UErrorCode & status) const562 FormattedNumber LocalizedNumberFormatter::formatDecimal(StringPiece value, UErrorCode& status) const {
563     if (U_FAILURE(status)) { return FormattedNumber(U_ILLEGAL_ARGUMENT_ERROR); }
564     auto results = new UFormattedNumberData();
565     if (results == nullptr) {
566         status = U_MEMORY_ALLOCATION_ERROR;
567         return FormattedNumber(status);
568     }
569     results->quantity.setToDecNumber(value, status);
570     formatImpl(results, status);
571 
572     // Do not save the results object if we encountered a failure.
573     if (U_SUCCESS(status)) {
574         return FormattedNumber(results);
575     } else {
576         delete results;
577         return FormattedNumber(status);
578     }
579 }
580 
581 FormattedNumber
formatDecimalQuantity(const DecimalQuantity & dq,UErrorCode & status) const582 LocalizedNumberFormatter::formatDecimalQuantity(const DecimalQuantity& dq, UErrorCode& status) const {
583     if (U_FAILURE(status)) { return FormattedNumber(U_ILLEGAL_ARGUMENT_ERROR); }
584     auto results = new UFormattedNumberData();
585     if (results == nullptr) {
586         status = U_MEMORY_ALLOCATION_ERROR;
587         return FormattedNumber(status);
588     }
589     results->quantity = dq;
590     formatImpl(results, status);
591 
592     // Do not save the results object if we encountered a failure.
593     if (U_SUCCESS(status)) {
594         return FormattedNumber(results);
595     } else {
596         delete results;
597         return FormattedNumber(status);
598     }
599 }
600 
formatImpl(impl::UFormattedNumberData * results,UErrorCode & status) const601 void LocalizedNumberFormatter::formatImpl(impl::UFormattedNumberData* results, UErrorCode& status) const {
602     if (computeCompiled(status)) {
603         fCompiled->format(results, status);
604     } else {
605         NumberFormatterImpl::formatStatic(fMacros, results, status);
606     }
607     if (U_FAILURE(status)) {
608         return;
609     }
610     results->getStringRef().writeTerminator(status);
611 }
612 
getAffixImpl(bool isPrefix,bool isNegative,UnicodeString & result,UErrorCode & status) const613 void LocalizedNumberFormatter::getAffixImpl(bool isPrefix, bool isNegative, UnicodeString& result,
614                                             UErrorCode& status) const {
615     FormattedStringBuilder string;
616     auto signum = static_cast<Signum>(isNegative ? SIGNUM_NEG : SIGNUM_POS);
617     // Always return affixes for plural form OTHER.
618     static const StandardPlural::Form plural = StandardPlural::OTHER;
619     int32_t prefixLength;
620     if (computeCompiled(status)) {
621         prefixLength = fCompiled->getPrefixSuffix(signum, plural, string, status);
622     } else {
623         prefixLength = NumberFormatterImpl::getPrefixSuffixStatic(fMacros, signum, plural, string, status);
624     }
625     result.remove();
626     if (isPrefix) {
627         result.append(string.toTempUnicodeString().tempSubStringBetween(0, prefixLength));
628     } else {
629         result.append(string.toTempUnicodeString().tempSubStringBetween(prefixLength, string.length()));
630     }
631 }
632 
computeCompiled(UErrorCode & status) const633 bool LocalizedNumberFormatter::computeCompiled(UErrorCode& status) const {
634     // fUnsafeCallCount contains memory to be interpreted as an atomic int, most commonly
635     // std::atomic<int32_t>.  Since the type of atomic int is platform-dependent, we cast the
636     // bytes in fUnsafeCallCount to u_atomic_int32_t, a typedef for the platform-dependent
637     // atomic int type defined in umutex.h.
638     static_assert(
639             sizeof(u_atomic_int32_t) <= sizeof(fUnsafeCallCount),
640             "Atomic integer size on this platform exceeds the size allocated by fUnsafeCallCount");
641     auto* callCount = reinterpret_cast<u_atomic_int32_t*>(
642             const_cast<LocalizedNumberFormatter*>(this)->fUnsafeCallCount);
643 
644     // A positive value in the atomic int indicates that the data structure is not yet ready;
645     // a negative value indicates that it is ready. If, after the increment, the atomic int
646     // is exactly threshold, then it is the current thread's job to build the data structure.
647     // Note: We set the callCount to INT32_MIN so that if another thread proceeds to increment
648     // the atomic int, the value remains below zero.
649     int32_t currentCount = umtx_loadAcquire(*callCount);
650     if (0 <= currentCount && currentCount <= fMacros.threshold && fMacros.threshold > 0) {
651         currentCount = umtx_atomic_inc(callCount);
652     }
653 
654     if (currentCount == fMacros.threshold && fMacros.threshold > 0) {
655         // Build the data structure and then use it (slow to fast path).
656         const NumberFormatterImpl* compiled = new NumberFormatterImpl(fMacros, status);
657         if (compiled == nullptr) {
658             status = U_MEMORY_ALLOCATION_ERROR;
659             return false;
660         }
661         U_ASSERT(fCompiled == nullptr);
662         const_cast<LocalizedNumberFormatter*>(this)->fCompiled = compiled;
663         umtx_storeRelease(*callCount, INT32_MIN);
664         return true;
665     } else if (currentCount < 0) {
666         // The data structure is already built; use it (fast path).
667         U_ASSERT(fCompiled != nullptr);
668         return true;
669     } else {
670         // Format the number without building the data structure (slow path).
671         return false;
672     }
673 }
674 
getCompiled() const675 const impl::NumberFormatterImpl* LocalizedNumberFormatter::getCompiled() const {
676     return fCompiled;
677 }
678 
getCallCount() const679 int32_t LocalizedNumberFormatter::getCallCount() const {
680     auto* callCount = reinterpret_cast<u_atomic_int32_t*>(
681             const_cast<LocalizedNumberFormatter*>(this)->fUnsafeCallCount);
682     return umtx_loadAcquire(*callCount);
683 }
684 
685 // Note: toFormat defined in number_asformat.cpp
686 
687 #if (U_PF_WINDOWS <= U_PLATFORM && U_PLATFORM <= U_PF_CYGWIN) && defined(_MSC_VER)
688 // Warning 4661.
689 #pragma warning(pop)
690 #endif
691 
692 #endif /* #if !UCONFIG_NO_FORMATTING */
693