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