blob: a66e3bd0f23510f610a975dacc7f69f8ab59ac4b [file] [log] [blame]
Jungshik Shinb3189662017-11-07 11:18:34 -08001// © 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
Jungshik Shina9a2bd32018-07-07 03:36:01 -07006#if !UCONFIG_NO_FORMATTING
Jungshik Shinb3189662017-11-07 11:18:34 -08007
8#include "uassert.h"
9#include "unicode/numberformatter.h"
10#include "number_decimalquantity.h"
11#include "number_formatimpl.h"
12#include "umutex.h"
Jungshik Shina9a2bd32018-07-07 03:36:01 -070013#include "number_asformat.h"
14#include "number_skeletons.h"
15#include "number_utils.h"
16#include "number_utypes.h"
17#include "util.h"
18#include "fphdlimp.h"
Jungshik Shinb3189662017-11-07 11:18:34 -080019
20using namespace icu;
21using namespace icu::number;
22using namespace icu::number::impl;
23
24template<typename Derived>
Jungshik Shina9a2bd32018-07-07 03:36:01 -070025Derived NumberFormatterSettings<Derived>::notation(const Notation& notation) const& {
Jungshik Shinb3189662017-11-07 11:18:34 -080026 Derived copy(*this);
27 // NOTE: Slicing is OK.
28 copy.fMacros.notation = notation;
29 return copy;
30}
31
32template<typename Derived>
Jungshik Shina9a2bd32018-07-07 03:36:01 -070033Derived NumberFormatterSettings<Derived>::notation(const Notation& notation)&& {
34 Derived move(std::move(*this));
35 // NOTE: Slicing is OK.
36 move.fMacros.notation = notation;
37 return move;
38}
39
40template<typename Derived>
41Derived NumberFormatterSettings<Derived>::unit(const icu::MeasureUnit& unit) const& {
Jungshik Shinb3189662017-11-07 11:18:34 -080042 Derived copy(*this);
43 // NOTE: Slicing occurs here. However, CurrencyUnit can be restored from MeasureUnit.
44 // TimeUnit may be affected, but TimeUnit is not as relevant to number formatting.
45 copy.fMacros.unit = unit;
46 return copy;
47}
48
49template<typename Derived>
Jungshik Shina9a2bd32018-07-07 03:36:01 -070050Derived NumberFormatterSettings<Derived>::unit(const icu::MeasureUnit& unit)&& {
51 Derived move(std::move(*this));
52 // See comments above about slicing.
53 move.fMacros.unit = unit;
54 return move;
55}
56
57template<typename Derived>
58Derived NumberFormatterSettings<Derived>::adoptUnit(icu::MeasureUnit* unit) const& {
Jungshik Shinb3189662017-11-07 11:18:34 -080059 Derived copy(*this);
Jungshik Shina9a2bd32018-07-07 03:36:01 -070060 // Just move the unit into the MacroProps by value, and delete it since we have ownership.
Jungshik Shinb3189662017-11-07 11:18:34 -080061 // NOTE: Slicing occurs here. However, CurrencyUnit can be restored from MeasureUnit.
62 // TimeUnit may be affected, but TimeUnit is not as relevant to number formatting.
63 if (unit != nullptr) {
Jungshik Shina9a2bd32018-07-07 03:36:01 -070064 // TODO: On nullptr, reset to default value?
65 copy.fMacros.unit = std::move(*unit);
Jungshik Shinb3189662017-11-07 11:18:34 -080066 delete unit;
67 }
68 return copy;
69}
70
71template<typename Derived>
Jungshik Shina9a2bd32018-07-07 03:36:01 -070072Derived NumberFormatterSettings<Derived>::adoptUnit(icu::MeasureUnit* unit)&& {
73 Derived move(std::move(*this));
74 // See comments above about slicing and ownership.
75 if (unit != nullptr) {
76 // TODO: On nullptr, reset to default value?
77 move.fMacros.unit = std::move(*unit);
78 delete unit;
79 }
80 return move;
81}
82
83template<typename Derived>
84Derived NumberFormatterSettings<Derived>::perUnit(const icu::MeasureUnit& perUnit) const& {
Jungshik Shinf61e46d2018-05-04 13:00:45 -070085 Derived copy(*this);
86 // See comments above about slicing.
87 copy.fMacros.perUnit = perUnit;
88 return copy;
89}
90
91template<typename Derived>
Jungshik Shina9a2bd32018-07-07 03:36:01 -070092Derived NumberFormatterSettings<Derived>::perUnit(const icu::MeasureUnit& perUnit)&& {
93 Derived move(std::move(*this));
94 // See comments above about slicing.
95 move.fMacros.perUnit = perUnit;
96 return move;
97}
98
99template<typename Derived>
100Derived NumberFormatterSettings<Derived>::adoptPerUnit(icu::MeasureUnit* perUnit) const& {
Jungshik Shinf61e46d2018-05-04 13:00:45 -0700101 Derived copy(*this);
102 // See comments above about slicing and ownership.
103 if (perUnit != nullptr) {
Jungshik Shina9a2bd32018-07-07 03:36:01 -0700104 // TODO: On nullptr, reset to default value?
105 copy.fMacros.perUnit = std::move(*perUnit);
Jungshik Shinf61e46d2018-05-04 13:00:45 -0700106 delete perUnit;
107 }
108 return copy;
109}
110
111template<typename Derived>
Jungshik Shina9a2bd32018-07-07 03:36:01 -0700112Derived NumberFormatterSettings<Derived>::adoptPerUnit(icu::MeasureUnit* perUnit)&& {
113 Derived move(std::move(*this));
114 // See comments above about slicing and ownership.
115 if (perUnit != nullptr) {
116 // TODO: On nullptr, reset to default value?
117 move.fMacros.perUnit = std::move(*perUnit);
118 delete perUnit;
119 }
120 return move;
121}
122
123template<typename Derived>
124Derived NumberFormatterSettings<Derived>::precision(const Precision& precision) const& {
Jungshik Shinb3189662017-11-07 11:18:34 -0800125 Derived copy(*this);
126 // NOTE: Slicing is OK.
Jungshik Shina9a2bd32018-07-07 03:36:01 -0700127 copy.fMacros.precision = precision;
Jungshik Shinb3189662017-11-07 11:18:34 -0800128 return copy;
129}
130
131template<typename Derived>
Jungshik Shina9a2bd32018-07-07 03:36:01 -0700132Derived NumberFormatterSettings<Derived>::precision(const Precision& precision)&& {
133 Derived move(std::move(*this));
134 // NOTE: Slicing is OK.
135 move.fMacros.precision = precision;
136 return move;
137}
138
139template<typename Derived>
140Derived NumberFormatterSettings<Derived>::roundingMode(UNumberFormatRoundingMode roundingMode) const& {
141 Derived copy(*this);
142 copy.fMacros.roundingMode = roundingMode;
143 return copy;
144}
145
146template<typename Derived>
147Derived NumberFormatterSettings<Derived>::roundingMode(UNumberFormatRoundingMode roundingMode)&& {
148 Derived move(std::move(*this));
149 move.fMacros.roundingMode = roundingMode;
150 return move;
151}
152
153template<typename Derived>
154Derived NumberFormatterSettings<Derived>::grouping(UGroupingStrategy strategy) const& {
Jungshik Shinb3189662017-11-07 11:18:34 -0800155 Derived copy(*this);
Jungshik Shinf61e46d2018-05-04 13:00:45 -0700156 // NOTE: This is slightly different than how the setting is stored in Java
157 // because we want to put it on the stack.
158 copy.fMacros.grouper = Grouper::forStrategy(strategy);
Jungshik Shinb3189662017-11-07 11:18:34 -0800159 return copy;
160}
161
162template<typename Derived>
Jungshik Shina9a2bd32018-07-07 03:36:01 -0700163Derived NumberFormatterSettings<Derived>::grouping(UGroupingStrategy strategy)&& {
164 Derived move(std::move(*this));
165 move.fMacros.grouper = Grouper::forStrategy(strategy);
166 return move;
167}
168
169template<typename Derived>
170Derived NumberFormatterSettings<Derived>::integerWidth(const IntegerWidth& style) const& {
Jungshik Shinb3189662017-11-07 11:18:34 -0800171 Derived copy(*this);
172 copy.fMacros.integerWidth = style;
173 return copy;
174}
175
176template<typename Derived>
Jungshik Shina9a2bd32018-07-07 03:36:01 -0700177Derived NumberFormatterSettings<Derived>::integerWidth(const IntegerWidth& style)&& {
178 Derived move(std::move(*this));
179 move.fMacros.integerWidth = style;
180 return move;
181}
182
183template<typename Derived>
184Derived NumberFormatterSettings<Derived>::symbols(const DecimalFormatSymbols& symbols) const& {
Jungshik Shinb3189662017-11-07 11:18:34 -0800185 Derived copy(*this);
186 copy.fMacros.symbols.setTo(symbols);
187 return copy;
188}
189
190template<typename Derived>
Jungshik Shina9a2bd32018-07-07 03:36:01 -0700191Derived NumberFormatterSettings<Derived>::symbols(const DecimalFormatSymbols& symbols)&& {
192 Derived move(std::move(*this));
193 move.fMacros.symbols.setTo(symbols);
194 return move;
195}
196
197template<typename Derived>
198Derived NumberFormatterSettings<Derived>::adoptSymbols(NumberingSystem* ns) const& {
Jungshik Shinb3189662017-11-07 11:18:34 -0800199 Derived copy(*this);
200 copy.fMacros.symbols.setTo(ns);
201 return copy;
202}
203
204template<typename Derived>
Jungshik Shina9a2bd32018-07-07 03:36:01 -0700205Derived NumberFormatterSettings<Derived>::adoptSymbols(NumberingSystem* ns)&& {
206 Derived move(std::move(*this));
207 move.fMacros.symbols.setTo(ns);
208 return move;
209}
210
211template<typename Derived>
212Derived NumberFormatterSettings<Derived>::unitWidth(UNumberUnitWidth width) const& {
Jungshik Shinb3189662017-11-07 11:18:34 -0800213 Derived copy(*this);
214 copy.fMacros.unitWidth = width;
215 return copy;
216}
217
218template<typename Derived>
Jungshik Shina9a2bd32018-07-07 03:36:01 -0700219Derived NumberFormatterSettings<Derived>::unitWidth(UNumberUnitWidth width)&& {
220 Derived move(std::move(*this));
221 move.fMacros.unitWidth = width;
222 return move;
223}
224
225template<typename Derived>
226Derived NumberFormatterSettings<Derived>::sign(UNumberSignDisplay style) const& {
Jungshik Shinb3189662017-11-07 11:18:34 -0800227 Derived copy(*this);
228 copy.fMacros.sign = style;
229 return copy;
230}
231
232template<typename Derived>
Jungshik Shina9a2bd32018-07-07 03:36:01 -0700233Derived NumberFormatterSettings<Derived>::sign(UNumberSignDisplay style)&& {
234 Derived move(std::move(*this));
235 move.fMacros.sign = style;
236 return move;
237}
238
239template<typename Derived>
240Derived NumberFormatterSettings<Derived>::decimal(UNumberDecimalSeparatorDisplay style) const& {
Jungshik Shinb3189662017-11-07 11:18:34 -0800241 Derived copy(*this);
242 copy.fMacros.decimal = style;
243 return copy;
244}
245
246template<typename Derived>
Jungshik Shina9a2bd32018-07-07 03:36:01 -0700247Derived NumberFormatterSettings<Derived>::decimal(UNumberDecimalSeparatorDisplay style)&& {
248 Derived move(std::move(*this));
249 move.fMacros.decimal = style;
250 return move;
251}
252
253template<typename Derived>
254Derived NumberFormatterSettings<Derived>::scale(const Scale& scale) const& {
255 Derived copy(*this);
256 copy.fMacros.scale = scale;
257 return copy;
258}
259
260template<typename Derived>
261Derived NumberFormatterSettings<Derived>::scale(const Scale& scale)&& {
262 Derived move(std::move(*this));
263 move.fMacros.scale = scale;
264 return move;
265}
266
267template<typename Derived>
268Derived NumberFormatterSettings<Derived>::padding(const Padder& padder) const& {
Jungshik Shinb3189662017-11-07 11:18:34 -0800269 Derived copy(*this);
270 copy.fMacros.padder = padder;
271 return copy;
272}
273
274template<typename Derived>
Jungshik Shina9a2bd32018-07-07 03:36:01 -0700275Derived NumberFormatterSettings<Derived>::padding(const Padder& padder)&& {
276 Derived move(std::move(*this));
277 move.fMacros.padder = padder;
278 return move;
279}
280
281template<typename Derived>
282Derived NumberFormatterSettings<Derived>::threshold(int32_t threshold) const& {
Jungshik Shinb3189662017-11-07 11:18:34 -0800283 Derived copy(*this);
284 copy.fMacros.threshold = threshold;
285 return copy;
286}
287
Jungshik Shina9a2bd32018-07-07 03:36:01 -0700288template<typename Derived>
289Derived NumberFormatterSettings<Derived>::threshold(int32_t threshold)&& {
290 Derived move(std::move(*this));
291 move.fMacros.threshold = threshold;
292 return move;
293}
294
295template<typename Derived>
296Derived NumberFormatterSettings<Derived>::macros(const impl::MacroProps& macros) const& {
297 Derived copy(*this);
298 copy.fMacros = macros;
299 return copy;
300}
301
302template<typename Derived>
303Derived NumberFormatterSettings<Derived>::macros(const impl::MacroProps& macros)&& {
304 Derived move(std::move(*this));
305 move.fMacros = macros;
306 return move;
307}
308
309template<typename Derived>
310Derived NumberFormatterSettings<Derived>::macros(impl::MacroProps&& macros) const& {
311 Derived copy(*this);
312 copy.fMacros = std::move(macros);
313 return copy;
314}
315
316template<typename Derived>
317Derived NumberFormatterSettings<Derived>::macros(impl::MacroProps&& macros)&& {
318 Derived move(std::move(*this));
319 move.fMacros = std::move(macros);
320 return move;
321}
322
323template<typename Derived>
324UnicodeString NumberFormatterSettings<Derived>::toSkeleton(UErrorCode& status) const {
325 if (fMacros.copyErrorTo(status)) {
326 return ICU_Utility::makeBogusString();
327 }
328 return skeleton::generate(fMacros, status);
329}
330
Jungshik Shinb3189662017-11-07 11:18:34 -0800331// Declare all classes that implement NumberFormatterSettings
332// See https://stackoverflow.com/a/495056/1407170
333template
334class icu::number::NumberFormatterSettings<icu::number::UnlocalizedNumberFormatter>;
335template
336class icu::number::NumberFormatterSettings<icu::number::LocalizedNumberFormatter>;
337
338
339UnlocalizedNumberFormatter NumberFormatter::with() {
340 UnlocalizedNumberFormatter result;
341 return result;
342}
343
Jungshik Shina9a2bd32018-07-07 03:36:01 -0700344LocalizedNumberFormatter NumberFormatter::withLocale(const Locale& locale) {
Jungshik Shinb3189662017-11-07 11:18:34 -0800345 return with().locale(locale);
346}
347
Jungshik Shina9a2bd32018-07-07 03:36:01 -0700348UnlocalizedNumberFormatter
349NumberFormatter::forSkeleton(const UnicodeString& skeleton, UErrorCode& status) {
350 return skeleton::create(skeleton, status);
Jungshik Shinb3189662017-11-07 11:18:34 -0800351}
352
Jungshik Shina9a2bd32018-07-07 03:36:01 -0700353
354template<typename T> using NFS = NumberFormatterSettings<T>;
355using LNF = LocalizedNumberFormatter;
356using UNF = UnlocalizedNumberFormatter;
357
358UnlocalizedNumberFormatter::UnlocalizedNumberFormatter(const UNF& other)
359 : UNF(static_cast<const NFS<UNF>&>(other)) {}
360
361UnlocalizedNumberFormatter::UnlocalizedNumberFormatter(const NFS<UNF>& other)
362 : NFS<UNF>(other) {
363 // No additional fields to assign
Jungshik Shinb3189662017-11-07 11:18:34 -0800364}
365
Jungshik Shin42d50272018-10-24 01:22:09 -0700366// Make default copy constructor call the NumberFormatterSettings copy constructor.
Jungshik Shina9a2bd32018-07-07 03:36:01 -0700367UnlocalizedNumberFormatter::UnlocalizedNumberFormatter(UNF&& src) U_NOEXCEPT
368 : UNF(static_cast<NFS<UNF>&&>(src)) {}
369
370UnlocalizedNumberFormatter::UnlocalizedNumberFormatter(NFS<UNF>&& src) U_NOEXCEPT
371 : NFS<UNF>(std::move(src)) {
372 // No additional fields to assign
373}
374
375UnlocalizedNumberFormatter& UnlocalizedNumberFormatter::operator=(const UNF& other) {
376 NFS<UNF>::operator=(static_cast<const NFS<UNF>&>(other));
377 // No additional fields to assign
378 return *this;
379}
380
381UnlocalizedNumberFormatter& UnlocalizedNumberFormatter::operator=(UNF&& src) U_NOEXCEPT {
382 NFS<UNF>::operator=(static_cast<NFS<UNF>&&>(src));
383 // No additional fields to assign
384 return *this;
385}
386
Jungshik Shin42d50272018-10-24 01:22:09 -0700387// Make default copy constructor call the NumberFormatterSettings copy constructor.
Jungshik Shina9a2bd32018-07-07 03:36:01 -0700388LocalizedNumberFormatter::LocalizedNumberFormatter(const LNF& other)
389 : LNF(static_cast<const NFS<LNF>&>(other)) {}
390
391LocalizedNumberFormatter::LocalizedNumberFormatter(const NFS<LNF>& other)
392 : NFS<LNF>(other) {
393 // No additional fields to assign (let call count and compiled formatter reset to defaults)
394}
395
396LocalizedNumberFormatter::LocalizedNumberFormatter(LocalizedNumberFormatter&& src) U_NOEXCEPT
397 : LNF(static_cast<NFS<LNF>&&>(src)) {}
398
399LocalizedNumberFormatter::LocalizedNumberFormatter(NFS<LNF>&& src) U_NOEXCEPT
400 : NFS<LNF>(std::move(src)) {
401 // For the move operators, copy over the compiled formatter.
402 // Note: if the formatter is not compiled, call count information is lost.
403 if (static_cast<LNF&&>(src).fCompiled != nullptr) {
404 lnfMoveHelper(static_cast<LNF&&>(src));
405 }
406}
407
408LocalizedNumberFormatter& LocalizedNumberFormatter::operator=(const LNF& other) {
409 NFS<LNF>::operator=(static_cast<const NFS<LNF>&>(other));
Jungshik Shin42d50272018-10-24 01:22:09 -0700410 // Reset to default values.
411 clear();
Jungshik Shina9a2bd32018-07-07 03:36:01 -0700412 return *this;
413}
414
415LocalizedNumberFormatter& LocalizedNumberFormatter::operator=(LNF&& src) U_NOEXCEPT {
416 NFS<LNF>::operator=(static_cast<NFS<LNF>&&>(src));
417 // For the move operators, copy over the compiled formatter.
418 // Note: if the formatter is not compiled, call count information is lost.
419 if (static_cast<LNF&&>(src).fCompiled != nullptr) {
420 // Formatter is compiled
421 lnfMoveHelper(static_cast<LNF&&>(src));
422 } else {
Jungshik Shin42d50272018-10-24 01:22:09 -0700423 clear();
Jungshik Shina9a2bd32018-07-07 03:36:01 -0700424 }
425 return *this;
426}
427
Jungshik Shin42d50272018-10-24 01:22:09 -0700428void LocalizedNumberFormatter::clear() {
429 // Reset to default values.
430 auto* callCount = reinterpret_cast<u_atomic_int32_t*>(fUnsafeCallCount);
431 umtx_storeRelease(*callCount, 0);
432 delete fCompiled;
433 fCompiled = nullptr;
434}
435
Jungshik Shina9a2bd32018-07-07 03:36:01 -0700436void LocalizedNumberFormatter::lnfMoveHelper(LNF&& src) {
437 // Copy over the compiled formatter and set call count to INT32_MIN as in computeCompiled().
438 // Don't copy the call count directly because doing so requires a loadAcquire/storeRelease.
439 // The bits themselves appear to be platform-dependent, so copying them might not be safe.
440 auto* callCount = reinterpret_cast<u_atomic_int32_t*>(fUnsafeCallCount);
441 umtx_storeRelease(*callCount, INT32_MIN);
Jungshik Shin42d50272018-10-24 01:22:09 -0700442 delete fCompiled;
Jungshik Shina9a2bd32018-07-07 03:36:01 -0700443 fCompiled = src.fCompiled;
444 // Reset the source object to leave it in a safe state.
445 auto* srcCallCount = reinterpret_cast<u_atomic_int32_t*>(src.fUnsafeCallCount);
446 umtx_storeRelease(*srcCallCount, 0);
447 src.fCompiled = nullptr;
448}
449
450
451LocalizedNumberFormatter::~LocalizedNumberFormatter() {
452 delete fCompiled;
453}
454
455LocalizedNumberFormatter::LocalizedNumberFormatter(const MacroProps& macros, const Locale& locale) {
Jungshik Shinb3189662017-11-07 11:18:34 -0800456 fMacros = macros;
457 fMacros.locale = locale;
458}
459
Jungshik Shina9a2bd32018-07-07 03:36:01 -0700460LocalizedNumberFormatter::LocalizedNumberFormatter(MacroProps&& macros, const Locale& locale) {
461 fMacros = std::move(macros);
462 fMacros.locale = locale;
463}
464
465LocalizedNumberFormatter UnlocalizedNumberFormatter::locale(const Locale& locale) const& {
Jungshik Shinb3189662017-11-07 11:18:34 -0800466 return LocalizedNumberFormatter(fMacros, locale);
467}
468
Jungshik Shina9a2bd32018-07-07 03:36:01 -0700469LocalizedNumberFormatter UnlocalizedNumberFormatter::locale(const Locale& locale)&& {
470 return LocalizedNumberFormatter(std::move(fMacros), locale);
471}
472
473SymbolsWrapper::SymbolsWrapper(const SymbolsWrapper& other) {
Jungshik Shinb3189662017-11-07 11:18:34 -0800474 doCopyFrom(other);
475}
476
Jungshik Shina9a2bd32018-07-07 03:36:01 -0700477SymbolsWrapper::SymbolsWrapper(SymbolsWrapper&& src) U_NOEXCEPT {
478 doMoveFrom(std::move(src));
479}
480
481SymbolsWrapper& SymbolsWrapper::operator=(const SymbolsWrapper& other) {
Jungshik Shinb3189662017-11-07 11:18:34 -0800482 if (this == &other) {
483 return *this;
484 }
485 doCleanup();
486 doCopyFrom(other);
487 return *this;
488}
489
Jungshik Shina9a2bd32018-07-07 03:36:01 -0700490SymbolsWrapper& SymbolsWrapper::operator=(SymbolsWrapper&& src) U_NOEXCEPT {
491 if (this == &src) {
492 return *this;
493 }
494 doCleanup();
495 doMoveFrom(std::move(src));
496 return *this;
497}
498
Jungshik Shinb3189662017-11-07 11:18:34 -0800499SymbolsWrapper::~SymbolsWrapper() {
500 doCleanup();
501}
502
Jungshik Shina9a2bd32018-07-07 03:36:01 -0700503void SymbolsWrapper::setTo(const DecimalFormatSymbols& dfs) {
Jungshik Shinb3189662017-11-07 11:18:34 -0800504 doCleanup();
505 fType = SYMPTR_DFS;
506 fPtr.dfs = new DecimalFormatSymbols(dfs);
507}
508
Jungshik Shina9a2bd32018-07-07 03:36:01 -0700509void SymbolsWrapper::setTo(const NumberingSystem* ns) {
Jungshik Shinb3189662017-11-07 11:18:34 -0800510 doCleanup();
511 fType = SYMPTR_NS;
512 fPtr.ns = ns;
513}
514
Jungshik Shina9a2bd32018-07-07 03:36:01 -0700515void SymbolsWrapper::doCopyFrom(const SymbolsWrapper& other) {
Jungshik Shinb3189662017-11-07 11:18:34 -0800516 fType = other.fType;
517 switch (fType) {
518 case SYMPTR_NONE:
519 // No action necessary
520 break;
521 case SYMPTR_DFS:
522 // Memory allocation failures are exposed in copyErrorTo()
523 if (other.fPtr.dfs != nullptr) {
524 fPtr.dfs = new DecimalFormatSymbols(*other.fPtr.dfs);
525 } else {
526 fPtr.dfs = nullptr;
527 }
528 break;
529 case SYMPTR_NS:
530 // Memory allocation failures are exposed in copyErrorTo()
531 if (other.fPtr.ns != nullptr) {
532 fPtr.ns = new NumberingSystem(*other.fPtr.ns);
533 } else {
534 fPtr.ns = nullptr;
535 }
536 break;
537 }
538}
539
Jungshik Shina9a2bd32018-07-07 03:36:01 -0700540void SymbolsWrapper::doMoveFrom(SymbolsWrapper&& src) {
541 fType = src.fType;
542 switch (fType) {
543 case SYMPTR_NONE:
544 // No action necessary
545 break;
546 case SYMPTR_DFS:
547 fPtr.dfs = src.fPtr.dfs;
548 src.fPtr.dfs = nullptr;
549 break;
550 case SYMPTR_NS:
551 fPtr.ns = src.fPtr.ns;
552 src.fPtr.ns = nullptr;
553 break;
554 }
555}
556
Jungshik Shinb3189662017-11-07 11:18:34 -0800557void SymbolsWrapper::doCleanup() {
558 switch (fType) {
559 case SYMPTR_NONE:
560 // No action necessary
561 break;
562 case SYMPTR_DFS:
563 delete fPtr.dfs;
564 break;
565 case SYMPTR_NS:
566 delete fPtr.ns;
567 break;
568 }
569}
570
571bool SymbolsWrapper::isDecimalFormatSymbols() const {
572 return fType == SYMPTR_DFS;
573}
574
575bool SymbolsWrapper::isNumberingSystem() const {
576 return fType == SYMPTR_NS;
577}
578
579const DecimalFormatSymbols* SymbolsWrapper::getDecimalFormatSymbols() const {
580 U_ASSERT(fType == SYMPTR_DFS);
581 return fPtr.dfs;
582}
583
584const NumberingSystem* SymbolsWrapper::getNumberingSystem() const {
585 U_ASSERT(fType == SYMPTR_NS);
586 return fPtr.ns;
587}
588
Jungshik Shinb3189662017-11-07 11:18:34 -0800589
Jungshik Shina9a2bd32018-07-07 03:36:01 -0700590FormattedNumber LocalizedNumberFormatter::formatInt(int64_t value, UErrorCode& status) const {
Jungshik Shinb3189662017-11-07 11:18:34 -0800591 if (U_FAILURE(status)) { return FormattedNumber(U_ILLEGAL_ARGUMENT_ERROR); }
Jungshik Shina9a2bd32018-07-07 03:36:01 -0700592 auto results = new UFormattedNumberData();
Jungshik Shinb3189662017-11-07 11:18:34 -0800593 if (results == nullptr) {
594 status = U_MEMORY_ALLOCATION_ERROR;
595 return FormattedNumber(status);
596 }
597 results->quantity.setToLong(value);
Jungshik Shina9a2bd32018-07-07 03:36:01 -0700598 formatImpl(results, status);
599
600 // Do not save the results object if we encountered a failure.
601 if (U_SUCCESS(status)) {
602 return FormattedNumber(results);
603 } else {
604 delete results;
605 return FormattedNumber(status);
606 }
Jungshik Shinb3189662017-11-07 11:18:34 -0800607}
608
Jungshik Shina9a2bd32018-07-07 03:36:01 -0700609FormattedNumber LocalizedNumberFormatter::formatDouble(double value, UErrorCode& status) const {
Jungshik Shinb3189662017-11-07 11:18:34 -0800610 if (U_FAILURE(status)) { return FormattedNumber(U_ILLEGAL_ARGUMENT_ERROR); }
Jungshik Shina9a2bd32018-07-07 03:36:01 -0700611 auto results = new UFormattedNumberData();
Jungshik Shinb3189662017-11-07 11:18:34 -0800612 if (results == nullptr) {
613 status = U_MEMORY_ALLOCATION_ERROR;
614 return FormattedNumber(status);
615 }
616 results->quantity.setToDouble(value);
Jungshik Shina9a2bd32018-07-07 03:36:01 -0700617 formatImpl(results, status);
618
619 // Do not save the results object if we encountered a failure.
620 if (U_SUCCESS(status)) {
621 return FormattedNumber(results);
622 } else {
623 delete results;
624 return FormattedNumber(status);
625 }
Jungshik Shinb3189662017-11-07 11:18:34 -0800626}
627
Jungshik Shina9a2bd32018-07-07 03:36:01 -0700628FormattedNumber LocalizedNumberFormatter::formatDecimal(StringPiece value, UErrorCode& status) const {
Jungshik Shinb3189662017-11-07 11:18:34 -0800629 if (U_FAILURE(status)) { return FormattedNumber(U_ILLEGAL_ARGUMENT_ERROR); }
Jungshik Shina9a2bd32018-07-07 03:36:01 -0700630 auto results = new UFormattedNumberData();
Jungshik Shinb3189662017-11-07 11:18:34 -0800631 if (results == nullptr) {
632 status = U_MEMORY_ALLOCATION_ERROR;
633 return FormattedNumber(status);
634 }
Jungshik Shina9a2bd32018-07-07 03:36:01 -0700635 results->quantity.setToDecNumber(value, status);
636 formatImpl(results, status);
637
638 // Do not save the results object if we encountered a failure.
639 if (U_SUCCESS(status)) {
640 return FormattedNumber(results);
641 } else {
642 delete results;
643 return FormattedNumber(status);
644 }
Jungshik Shinb3189662017-11-07 11:18:34 -0800645}
646
647FormattedNumber
Jungshik Shina9a2bd32018-07-07 03:36:01 -0700648LocalizedNumberFormatter::formatDecimalQuantity(const DecimalQuantity& dq, UErrorCode& status) const {
649 if (U_FAILURE(status)) { return FormattedNumber(U_ILLEGAL_ARGUMENT_ERROR); }
650 auto results = new UFormattedNumberData();
651 if (results == nullptr) {
652 status = U_MEMORY_ALLOCATION_ERROR;
653 return FormattedNumber(status);
654 }
655 results->quantity = dq;
656 formatImpl(results, status);
657
658 // Do not save the results object if we encountered a failure.
659 if (U_SUCCESS(status)) {
660 return FormattedNumber(results);
661 } else {
662 delete results;
663 return FormattedNumber(status);
664 }
665}
666
667void LocalizedNumberFormatter::formatImpl(impl::UFormattedNumberData* results, UErrorCode& status) const {
668 if (computeCompiled(status)) {
Jungshik Shin42d50272018-10-24 01:22:09 -0700669 fCompiled->format(results->quantity, results->string, status);
Jungshik Shina9a2bd32018-07-07 03:36:01 -0700670 } else {
Jungshik Shin42d50272018-10-24 01:22:09 -0700671 NumberFormatterImpl::formatStatic(fMacros, results->quantity, results->string, status);
Jungshik Shina9a2bd32018-07-07 03:36:01 -0700672 }
673}
674
675void LocalizedNumberFormatter::getAffixImpl(bool isPrefix, bool isNegative, UnicodeString& result,
676 UErrorCode& status) const {
677 NumberStringBuilder string;
678 auto signum = static_cast<int8_t>(isNegative ? -1 : 1);
679 // Always return affixes for plural form OTHER.
680 static const StandardPlural::Form plural = StandardPlural::OTHER;
681 int32_t prefixLength;
682 if (computeCompiled(status)) {
683 prefixLength = fCompiled->getPrefixSuffix(signum, plural, string, status);
684 } else {
685 prefixLength = NumberFormatterImpl::getPrefixSuffixStatic(fMacros, signum, plural, string, status);
686 }
687 result.remove();
688 if (isPrefix) {
689 result.append(string.toTempUnicodeString().tempSubStringBetween(0, prefixLength));
690 } else {
691 result.append(string.toTempUnicodeString().tempSubStringBetween(prefixLength, string.length()));
692 }
693}
694
695bool LocalizedNumberFormatter::computeCompiled(UErrorCode& status) const {
Jungshik Shinb3189662017-11-07 11:18:34 -0800696 // fUnsafeCallCount contains memory to be interpreted as an atomic int, most commonly
697 // std::atomic<int32_t>. Since the type of atomic int is platform-dependent, we cast the
698 // bytes in fUnsafeCallCount to u_atomic_int32_t, a typedef for the platform-dependent
699 // atomic int type defined in umutex.h.
Jungshik Shina9a2bd32018-07-07 03:36:01 -0700700 static_assert(
701 sizeof(u_atomic_int32_t) <= sizeof(fUnsafeCallCount),
702 "Atomic integer size on this platform exceeds the size allocated by fUnsafeCallCount");
703 auto* callCount = reinterpret_cast<u_atomic_int32_t*>(
704 const_cast<LocalizedNumberFormatter*>(this)->fUnsafeCallCount);
Jungshik Shinb3189662017-11-07 11:18:34 -0800705
706 // A positive value in the atomic int indicates that the data structure is not yet ready;
707 // a negative value indicates that it is ready. If, after the increment, the atomic int
708 // is exactly threshold, then it is the current thread's job to build the data structure.
709 // Note: We set the callCount to INT32_MIN so that if another thread proceeds to increment
710 // the atomic int, the value remains below zero.
711 int32_t currentCount = umtx_loadAcquire(*callCount);
712 if (0 <= currentCount && currentCount <= fMacros.threshold && fMacros.threshold > 0) {
713 currentCount = umtx_atomic_inc(callCount);
714 }
715
716 if (currentCount == fMacros.threshold && fMacros.threshold > 0) {
717 // Build the data structure and then use it (slow to fast path).
Jungshik Shin42d50272018-10-24 01:22:09 -0700718 const NumberFormatterImpl* compiled = new NumberFormatterImpl(fMacros, status);
719 if (compiled == nullptr) {
720 status = U_MEMORY_ALLOCATION_ERROR;
721 return false;
722 }
Jungshik Shinb3189662017-11-07 11:18:34 -0800723 U_ASSERT(fCompiled == nullptr);
Jungshik Shina9a2bd32018-07-07 03:36:01 -0700724 const_cast<LocalizedNumberFormatter*>(this)->fCompiled = compiled;
Jungshik Shinb3189662017-11-07 11:18:34 -0800725 umtx_storeRelease(*callCount, INT32_MIN);
Jungshik Shina9a2bd32018-07-07 03:36:01 -0700726 return true;
Jungshik Shinb3189662017-11-07 11:18:34 -0800727 } else if (currentCount < 0) {
728 // The data structure is already built; use it (fast path).
729 U_ASSERT(fCompiled != nullptr);
Jungshik Shina9a2bd32018-07-07 03:36:01 -0700730 return true;
Jungshik Shinb3189662017-11-07 11:18:34 -0800731 } else {
732 // Format the number without building the data structure (slow path).
Jungshik Shina9a2bd32018-07-07 03:36:01 -0700733 return false;
Jungshik Shinb3189662017-11-07 11:18:34 -0800734 }
735}
736
Jungshik Shina9a2bd32018-07-07 03:36:01 -0700737const impl::NumberFormatterImpl* LocalizedNumberFormatter::getCompiled() const {
738 return fCompiled;
739}
740
741int32_t LocalizedNumberFormatter::getCallCount() const {
742 auto* callCount = reinterpret_cast<u_atomic_int32_t*>(
743 const_cast<LocalizedNumberFormatter*>(this)->fUnsafeCallCount);
744 return umtx_loadAcquire(*callCount);
745}
746
747Format* LocalizedNumberFormatter::toFormat(UErrorCode& status) const {
748 LocalPointer<LocalizedNumberFormatterAsFormat> retval(
749 new LocalizedNumberFormatterAsFormat(*this, fMacros.locale), status);
750 return retval.orphan();
751}
752
753
754FormattedNumber::FormattedNumber(FormattedNumber&& src) U_NOEXCEPT
755 : fResults(src.fResults), fErrorCode(src.fErrorCode) {
756 // Disown src.fResults to prevent double-deletion
757 src.fResults = nullptr;
758 src.fErrorCode = U_INVALID_STATE_ERROR;
759}
760
761FormattedNumber& FormattedNumber::operator=(FormattedNumber&& src) U_NOEXCEPT {
762 delete fResults;
763 fResults = src.fResults;
764 fErrorCode = src.fErrorCode;
765 // Disown src.fResults to prevent double-deletion
766 src.fResults = nullptr;
767 src.fErrorCode = U_INVALID_STATE_ERROR;
768 return *this;
769}
770
Jungshik Shinb3189662017-11-07 11:18:34 -0800771UnicodeString FormattedNumber::toString() const {
Jungshik Shina9a2bd32018-07-07 03:36:01 -0700772 UErrorCode localStatus = U_ZERO_ERROR;
773 return toString(localStatus);
774}
775
776UnicodeString FormattedNumber::toString(UErrorCode& status) const {
777 if (U_FAILURE(status)) {
778 return ICU_Utility::makeBogusString();
779 }
Jungshik Shinb3189662017-11-07 11:18:34 -0800780 if (fResults == nullptr) {
Jungshik Shina9a2bd32018-07-07 03:36:01 -0700781 status = fErrorCode;
782 return ICU_Utility::makeBogusString();
Jungshik Shinb3189662017-11-07 11:18:34 -0800783 }
784 return fResults->string.toUnicodeString();
785}
786
Jungshik Shina9a2bd32018-07-07 03:36:01 -0700787Appendable& FormattedNumber::appendTo(Appendable& appendable) {
788 UErrorCode localStatus = U_ZERO_ERROR;
789 return appendTo(appendable, localStatus);
790}
791
Jungshik Shin42d50272018-10-24 01:22:09 -0700792Appendable& FormattedNumber::appendTo(Appendable& appendable, UErrorCode& status) const {
Jungshik Shina9a2bd32018-07-07 03:36:01 -0700793 if (U_FAILURE(status)) {
794 return appendable;
795 }
Jungshik Shinb3189662017-11-07 11:18:34 -0800796 if (fResults == nullptr) {
Jungshik Shina9a2bd32018-07-07 03:36:01 -0700797 status = fErrorCode;
Jungshik Shinb3189662017-11-07 11:18:34 -0800798 return appendable;
799 }
800 appendable.appendString(fResults->string.chars(), fResults->string.length());
801 return appendable;
802}
803
Jungshik Shina9a2bd32018-07-07 03:36:01 -0700804void FormattedNumber::populateFieldPosition(FieldPosition& fieldPosition, UErrorCode& status) {
805 if (U_FAILURE(status)) {
806 return;
807 }
Jungshik Shinb3189662017-11-07 11:18:34 -0800808 if (fResults == nullptr) {
809 status = fErrorCode;
810 return;
811 }
Jungshik Shina9a2bd32018-07-07 03:36:01 -0700812 // in case any users were depending on the old behavior:
813 fieldPosition.setBeginIndex(0);
814 fieldPosition.setEndIndex(0);
815 fResults->string.nextFieldPosition(fieldPosition, status);
Jungshik Shinb3189662017-11-07 11:18:34 -0800816}
817
Jungshik Shina9a2bd32018-07-07 03:36:01 -0700818UBool FormattedNumber::nextFieldPosition(FieldPosition& fieldPosition, UErrorCode& status) const {
819 if (U_FAILURE(status)) {
820 return FALSE;
821 }
822 if (fResults == nullptr) {
823 status = fErrorCode;
824 return FALSE;
825 }
826 // NOTE: MSVC sometimes complains when implicitly converting between bool and UBool
827 return fResults->string.nextFieldPosition(fieldPosition, status) ? TRUE : FALSE;
828}
829
830void FormattedNumber::populateFieldPositionIterator(FieldPositionIterator& iterator, UErrorCode& status) {
831 getAllFieldPositions(iterator, status);
832}
833
834void FormattedNumber::getAllFieldPositions(FieldPositionIterator& iterator, UErrorCode& status) const {
835 FieldPositionIteratorHandler fpih(&iterator, status);
836 getAllFieldPositionsImpl(fpih, status);
837}
838
839void FormattedNumber::getAllFieldPositionsImpl(FieldPositionIteratorHandler& fpih,
840 UErrorCode& status) const {
841 if (U_FAILURE(status)) {
842 return;
843 }
Jungshik Shinb3189662017-11-07 11:18:34 -0800844 if (fResults == nullptr) {
845 status = fErrorCode;
846 return;
847 }
Jungshik Shina9a2bd32018-07-07 03:36:01 -0700848 fResults->string.getAllFieldPositions(fpih, status);
849}
850
851void FormattedNumber::getDecimalQuantity(DecimalQuantity& output, UErrorCode& status) const {
852 if (U_FAILURE(status)) {
853 return;
854 }
855 if (fResults == nullptr) {
856 status = fErrorCode;
857 return;
858 }
859 output = fResults->quantity;
Jungshik Shinb3189662017-11-07 11:18:34 -0800860}
861
862FormattedNumber::~FormattedNumber() {
863 delete fResults;
864}
865
866#endif /* #if !UCONFIG_NO_FORMATTING */