• 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 
UnlocalizedNumberFormatter(const impl::MacroProps & macros)433 UnlocalizedNumberFormatter::UnlocalizedNumberFormatter(const impl::MacroProps &macros) {
434     fMacros = macros;
435 }
436 
UnlocalizedNumberFormatter(impl::MacroProps && macros)437 UnlocalizedNumberFormatter::UnlocalizedNumberFormatter(impl::MacroProps &&macros) {
438     fMacros = macros;
439 }
440 
441 // Make default copy constructor call the NumberFormatterSettings copy constructor.
UnlocalizedNumberFormatter(UNF && src)442 UnlocalizedNumberFormatter::UnlocalizedNumberFormatter(UNF&& src) noexcept
443         : UNF(static_cast<NFS<UNF>&&>(src)) {}
444 
UnlocalizedNumberFormatter(NFS<UNF> && src)445 UnlocalizedNumberFormatter::UnlocalizedNumberFormatter(NFS<UNF>&& src) noexcept
446         : NFS<UNF>(std::move(src)) {
447     // No additional fields to assign
448 }
449 
operator =(const UNF & other)450 UnlocalizedNumberFormatter& UnlocalizedNumberFormatter::operator=(const UNF& other) {
451     NFS<UNF>::operator=(static_cast<const NFS<UNF>&>(other));
452     // No additional fields to assign
453     return *this;
454 }
455 
operator =(UNF && src)456 UnlocalizedNumberFormatter& UnlocalizedNumberFormatter::operator=(UNF&& src) noexcept {
457     NFS<UNF>::operator=(static_cast<NFS<UNF>&&>(src));
458     // No additional fields to assign
459     return *this;
460 }
461 
462 // Make default copy constructor call the NumberFormatterSettings copy constructor.
LocalizedNumberFormatter(const LNF & other)463 LocalizedNumberFormatter::LocalizedNumberFormatter(const LNF& other)
464         : LNF(static_cast<const NFS<LNF>&>(other)) {}
465 
LocalizedNumberFormatter(const NFS<LNF> & other)466 LocalizedNumberFormatter::LocalizedNumberFormatter(const NFS<LNF>& other)
467         : NFS<LNF>(other) {
468     UErrorCode localStatus = U_ZERO_ERROR; // Can't bubble up the error
469     lnfCopyHelper(static_cast<const LNF&>(other), localStatus);
470 }
471 
LocalizedNumberFormatter(LocalizedNumberFormatter && src)472 LocalizedNumberFormatter::LocalizedNumberFormatter(LocalizedNumberFormatter&& src) noexcept
473         : LNF(static_cast<NFS<LNF>&&>(src)) {}
474 
LocalizedNumberFormatter(NFS<LNF> && src)475 LocalizedNumberFormatter::LocalizedNumberFormatter(NFS<LNF>&& src) noexcept
476         : NFS<LNF>(std::move(src)) {
477     lnfMoveHelper(std::move(static_cast<LNF&&>(src)));
478 }
479 
operator =(const LNF & other)480 LocalizedNumberFormatter& LocalizedNumberFormatter::operator=(const LNF& other) {
481     if (this == &other) { return *this; }  // self-assignment: no-op
482     NFS<LNF>::operator=(static_cast<const NFS<LNF>&>(other));
483     UErrorCode localStatus = U_ZERO_ERROR; // Can't bubble up the error
484     lnfCopyHelper(other, localStatus);
485     return *this;
486 }
487 
operator =(LNF && src)488 LocalizedNumberFormatter& LocalizedNumberFormatter::operator=(LNF&& src) noexcept {
489     NFS<LNF>::operator=(static_cast<NFS<LNF>&&>(src));
490     lnfMoveHelper(std::move(src));
491     return *this;
492 }
493 
resetCompiled()494 void LocalizedNumberFormatter::resetCompiled() {
495     auto* callCount = reinterpret_cast<u_atomic_int32_t*>(fUnsafeCallCount);
496     umtx_storeRelease(*callCount, 0);
497     fCompiled = nullptr;
498 }
499 
lnfMoveHelper(LNF && src)500 void LocalizedNumberFormatter::lnfMoveHelper(LNF&& src) {
501     // Copy over the compiled formatter and set call count to INT32_MIN as in computeCompiled().
502     // Don't copy the call count directly because doing so requires a loadAcquire/storeRelease.
503     // The bits themselves appear to be platform-dependent, so copying them might not be safe.
504     delete fCompiled;
505     if (src.fCompiled != nullptr) {
506         auto* callCount = reinterpret_cast<u_atomic_int32_t*>(fUnsafeCallCount);
507         umtx_storeRelease(*callCount, INT32_MIN);
508         fCompiled = src.fCompiled;
509         // Reset the source object to leave it in a safe state.
510         src.resetCompiled();
511     } else {
512         resetCompiled();
513     }
514 
515     // Unconditionally move the warehouse
516     delete fWarehouse;
517     fWarehouse = src.fWarehouse;
518     src.fWarehouse = nullptr;
519 }
520 
lnfCopyHelper(const LNF &,UErrorCode & status)521 void LocalizedNumberFormatter::lnfCopyHelper(const LNF&, UErrorCode& status) {
522     // When copying, always reset the compiled formatter.
523     delete fCompiled;
524     resetCompiled();
525 
526     // If MacroProps has a reference to AffixPatternProvider, we need to copy it.
527     // If MacroProps has a reference to PluralRules, copy that one, too.
528     delete fWarehouse;
529     if (fMacros.affixProvider || fMacros.rules) {
530         LocalPointer<DecimalFormatWarehouse> warehouse(new DecimalFormatWarehouse(), status);
531         if (U_FAILURE(status)) {
532             fWarehouse = nullptr;
533             return;
534         }
535         if (fMacros.affixProvider) {
536             warehouse->affixProvider.setTo(fMacros.affixProvider, status);
537             fMacros.affixProvider = &warehouse->affixProvider.get();
538         }
539         if (fMacros.rules) {
540             warehouse->rules.adoptInsteadAndCheckErrorCode(
541                 new PluralRules(*fMacros.rules), status);
542             fMacros.rules = warehouse->rules.getAlias();
543         }
544         fWarehouse = warehouse.orphan();
545     } else {
546         fWarehouse = nullptr;
547     }
548 }
549 
550 
~LocalizedNumberFormatter()551 LocalizedNumberFormatter::~LocalizedNumberFormatter() {
552     delete fCompiled;
553     delete fWarehouse;
554 }
555 
LocalizedNumberFormatter(const MacroProps & macros,const Locale & locale)556 LocalizedNumberFormatter::LocalizedNumberFormatter(const MacroProps& macros, const Locale& locale) {
557     fMacros = macros;
558     fMacros.locale = locale;
559 }
560 
LocalizedNumberFormatter(MacroProps && macros,const Locale & locale)561 LocalizedNumberFormatter::LocalizedNumberFormatter(MacroProps&& macros, const Locale& locale) {
562     fMacros = std::move(macros);
563     fMacros.locale = locale;
564 }
565 
locale(const Locale & locale) const566 LocalizedNumberFormatter UnlocalizedNumberFormatter::locale(const Locale& locale) const& {
567     return LocalizedNumberFormatter(fMacros, locale);
568 }
569 
locale(const Locale & locale)570 LocalizedNumberFormatter UnlocalizedNumberFormatter::locale(const Locale& locale)&& {
571     return LocalizedNumberFormatter(std::move(fMacros), locale);
572 }
573 
formatInt(int64_t value,UErrorCode & status) const574 FormattedNumber LocalizedNumberFormatter::formatInt(int64_t value, UErrorCode& status) const {
575     if (U_FAILURE(status)) { return FormattedNumber(U_ILLEGAL_ARGUMENT_ERROR); }
576     auto* results = new UFormattedNumberData();
577     if (results == nullptr) {
578         status = U_MEMORY_ALLOCATION_ERROR;
579         return FormattedNumber(status);
580     }
581     results->quantity.setToLong(value);
582     formatImpl(results, status);
583 
584     // Do not save the results object if we encountered a failure.
585     if (U_SUCCESS(status)) {
586         return FormattedNumber(results);
587     } else {
588         delete results;
589         return FormattedNumber(status);
590     }
591 }
592 
formatDouble(double value,UErrorCode & status) const593 FormattedNumber LocalizedNumberFormatter::formatDouble(double value, UErrorCode& status) const {
594     if (U_FAILURE(status)) { return FormattedNumber(U_ILLEGAL_ARGUMENT_ERROR); }
595     auto* results = new UFormattedNumberData();
596     if (results == nullptr) {
597         status = U_MEMORY_ALLOCATION_ERROR;
598         return FormattedNumber(status);
599     }
600     results->quantity.setToDouble(value);
601     formatImpl(results, status);
602 
603     // Do not save the results object if we encountered a failure.
604     if (U_SUCCESS(status)) {
605         return FormattedNumber(results);
606     } else {
607         delete results;
608         return FormattedNumber(status);
609     }
610 }
611 
formatDecimal(StringPiece value,UErrorCode & status) const612 FormattedNumber LocalizedNumberFormatter::formatDecimal(StringPiece value, UErrorCode& status) const {
613     if (U_FAILURE(status)) { return FormattedNumber(U_ILLEGAL_ARGUMENT_ERROR); }
614     auto* results = new UFormattedNumberData();
615     if (results == nullptr) {
616         status = U_MEMORY_ALLOCATION_ERROR;
617         return FormattedNumber(status);
618     }
619     results->quantity.setToDecNumber(value, status);
620     formatImpl(results, status);
621 
622     // Do not save the results object if we encountered a failure.
623     if (U_SUCCESS(status)) {
624         return FormattedNumber(results);
625     } else {
626         delete results;
627         return FormattedNumber(status);
628     }
629 }
630 
631 FormattedNumber
formatDecimalQuantity(const DecimalQuantity & dq,UErrorCode & status) const632 LocalizedNumberFormatter::formatDecimalQuantity(const DecimalQuantity& dq, UErrorCode& status) const {
633     if (U_FAILURE(status)) { return FormattedNumber(U_ILLEGAL_ARGUMENT_ERROR); }
634     auto* results = new UFormattedNumberData();
635     if (results == nullptr) {
636         status = U_MEMORY_ALLOCATION_ERROR;
637         return FormattedNumber(status);
638     }
639     results->quantity = dq;
640     formatImpl(results, status);
641 
642     // Do not save the results object if we encountered a failure.
643     if (U_SUCCESS(status)) {
644         return FormattedNumber(results);
645     } else {
646         delete results;
647         return FormattedNumber(status);
648     }
649 }
650 
formatImpl(impl::UFormattedNumberData * results,UErrorCode & status) const651 void LocalizedNumberFormatter::formatImpl(impl::UFormattedNumberData* results, UErrorCode& status) const {
652     if (computeCompiled(status)) {
653         fCompiled->format(results, status);
654     } else {
655         NumberFormatterImpl::formatStatic(fMacros, results, status);
656     }
657     if (U_FAILURE(status)) {
658         return;
659     }
660     results->getStringRef().writeTerminator(status);
661 }
662 
getAffixImpl(bool isPrefix,bool isNegative,UnicodeString & result,UErrorCode & status) const663 void LocalizedNumberFormatter::getAffixImpl(bool isPrefix, bool isNegative, UnicodeString& result,
664                                             UErrorCode& status) const {
665     FormattedStringBuilder string;
666     auto signum = static_cast<Signum>(isNegative ? SIGNUM_NEG : SIGNUM_POS);
667     // Always return affixes for plural form OTHER.
668     static const StandardPlural::Form plural = StandardPlural::OTHER;
669     int32_t prefixLength;
670     if (computeCompiled(status)) {
671         prefixLength = fCompiled->getPrefixSuffix(signum, plural, string, status);
672     } else {
673         prefixLength = NumberFormatterImpl::getPrefixSuffixStatic(fMacros, signum, plural, string, status);
674     }
675     result.remove();
676     if (isPrefix) {
677         result.append(string.toTempUnicodeString().tempSubStringBetween(0, prefixLength));
678     } else {
679         result.append(string.toTempUnicodeString().tempSubStringBetween(prefixLength, string.length()));
680     }
681 }
682 
computeCompiled(UErrorCode & status) const683 bool LocalizedNumberFormatter::computeCompiled(UErrorCode& status) const {
684     // fUnsafeCallCount contains memory to be interpreted as an atomic int, most commonly
685     // std::atomic<int32_t>.  Since the type of atomic int is platform-dependent, we cast the
686     // bytes in fUnsafeCallCount to u_atomic_int32_t, a typedef for the platform-dependent
687     // atomic int type defined in umutex.h.
688     static_assert(
689             sizeof(u_atomic_int32_t) <= sizeof(fUnsafeCallCount),
690             "Atomic integer size on this platform exceeds the size allocated by fUnsafeCallCount");
691     auto* callCount = reinterpret_cast<u_atomic_int32_t*>(
692             const_cast<LocalizedNumberFormatter*>(this)->fUnsafeCallCount);
693 
694     // A positive value in the atomic int indicates that the data structure is not yet ready;
695     // a negative value indicates that it is ready. If, after the increment, the atomic int
696     // is exactly threshold, then it is the current thread's job to build the data structure.
697     // Note: We set the callCount to INT32_MIN so that if another thread proceeds to increment
698     // the atomic int, the value remains below zero.
699     int32_t currentCount = umtx_loadAcquire(*callCount);
700     if (0 <= currentCount && currentCount <= fMacros.threshold && fMacros.threshold > 0) {
701         currentCount = umtx_atomic_inc(callCount);
702     }
703 
704     if (currentCount == fMacros.threshold && fMacros.threshold > 0) {
705         // Build the data structure and then use it (slow to fast path).
706         const NumberFormatterImpl* compiled = new NumberFormatterImpl(fMacros, status);
707         if (compiled == nullptr) {
708             status = U_MEMORY_ALLOCATION_ERROR;
709             return false;
710         }
711         U_ASSERT(fCompiled == nullptr);
712         const_cast<LocalizedNumberFormatter*>(this)->fCompiled = compiled;
713         umtx_storeRelease(*callCount, INT32_MIN);
714         return true;
715     } else if (currentCount < 0) {
716         // The data structure is already built; use it (fast path).
717         U_ASSERT(fCompiled != nullptr);
718         return true;
719     } else {
720         // Format the number without building the data structure (slow path).
721         return false;
722     }
723 }
724 
getCompiled() const725 const impl::NumberFormatterImpl* LocalizedNumberFormatter::getCompiled() const {
726     return fCompiled;
727 }
728 
getCallCount() const729 int32_t LocalizedNumberFormatter::getCallCount() const {
730     auto* callCount = reinterpret_cast<u_atomic_int32_t*>(
731             const_cast<LocalizedNumberFormatter*>(this)->fUnsafeCallCount);
732     return umtx_loadAcquire(*callCount);
733 }
734 
735 // Note: toFormat defined in number_asformat.cpp
736 
withoutLocale() const737 UnlocalizedNumberFormatter LocalizedNumberFormatter::withoutLocale() const & {
738     MacroProps macros(fMacros);
739     macros.locale = Locale();
740     return UnlocalizedNumberFormatter(macros);
741 }
742 
withoutLocale()743 UnlocalizedNumberFormatter LocalizedNumberFormatter::withoutLocale() && {
744     MacroProps macros(std::move(fMacros));
745     macros.locale = Locale();
746     return UnlocalizedNumberFormatter(std::move(macros));
747 }
748 
getDecimalFormatSymbols() const749 const DecimalFormatSymbols* LocalizedNumberFormatter::getDecimalFormatSymbols() const {
750     return fMacros.symbols.getDecimalFormatSymbols();
751 }
752 
753 #if (U_PF_WINDOWS <= U_PLATFORM && U_PLATFORM <= U_PF_CYGWIN) && defined(_MSC_VER)
754 // Warning 4661.
755 #pragma warning(pop)
756 #endif
757 
758 #endif /* #if !UCONFIG_NO_FORMATTING */
759