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